# SprintFlint free tools for AI agents Use this local subprocess interface to calculate sprint metrics, ask team questionnaires and generate editable planning documents. All 15 public tools share their calculation functions, rules and templates with SprintFlint's browser tools. The download requires Node.js 24. Running it requires no repository checkout, Rails, npm installation, signup, credentials or network access. The repository also provides the same interface at `bin/free-tools`. Download and reference URLs: - Bundle: https://sprintflint.com/downloads/sprintflint-free-tools.mjs - Schema manifest: https://sprintflint.com/downloads/sprintflint-free-tools.json - This guide: https://sprintflint.com/downloads/sprintflint-free-tools-agent-guide.md ## Discover → describe → run ```sh curl --fail --location https://sprintflint.com/downloads/sprintflint-free-tools.mjs \ --output sprintflint-free-tools.mjs node sprintflint-free-tools.mjs discover > tools.json node sprintflint-free-tools.mjs describe velocity-calculator > velocity-contract.json node sprintflint-free-tools.mjs example velocity-calculator > velocity-input.json # Replace example values with the user's actual team data. node sprintflint-free-tools.mjs run velocity-calculator --input velocity-input.json ``` `discover` returns a compact catalogue of slugs, descriptions, URLs, supported formats and command syntax. `describe TOOL` returns one contract: description, browser URL, JSON Schema input/output shapes, supported formats, units, required fields, constraints, defaults, and paired input/output examples. Questionnaire schemas include the question text and labelled choices under `answers`. Ask those questions and collect actual team answers. `example` gives input values, **not a schema**. `list` remains a compact slug/URL list. Schemas use JSON Schema draft 2020-12. Inputs reject unknown fields, nulls, wrong types, empty/whitespace text, invalid choices and invalid calendar dates. Numeric inputs are finite and bounded by the schema. Fractional values are supported unless a field has `type: integer`. The validator implements the schema keywords used by these contracts. The manifest documents all `x-` annotations/extensions: `x-unit`, `x-choices`, `x-weight`, `x-category`, `x-media-type`, `x-default` and `x-arrayLengthMaximum`. Absent optional fields receive their declared defaults. `x-default: utc-today` means the current UTC YYYY-MM-DD, so pass an explicit date for reproducibility. Burndown's `x-arrayLengthMaximum` requires `daily.length <= sprintLength`. Sprint review's conditional schema requires at least 40 minutes for sync and at least 30 for async/hybrid. Extremely large inputs whose results exceed supported numeric or four-digit calendar bounds fail with `COMPUTATION_ERROR`. The schema manifest includes the full catalogue of contracts and adds `distribution.url`, `distribution.sha256`, `distribution.bytes` and the build-tool version. Compare the local bundle's SHA-256 with the manifest if verifying a download. Stable URLs revalidate on every request; store the digest/version with a reproducible planning run. ## Chain historical velocity into capacity and a forecast Read the three contracts before constructing inputs. The velocity result's `average` and `standardDeviation` are inputs to the next calculations. Capacity uses **working days**, while the forecaster uses **calendar weeks**. PTO is total **person-days for the team**, not days per person. This executable Node example starts with the catalogue, obtains each schema, fills every required field, uses real subprocess results, and prints one final JSON report. Replace the sample history and planning assumptions with the user's data. It uses only Node's built-in modules and the downloaded bundle. ```sh node --input-type=module <<'JS' import { spawnSync } from 'node:child_process' import { resolve } from 'node:path' const bundle = resolve('sprintflint-free-tools.mjs') function cli(args, input) { const child = spawnSync(process.execPath, [bundle, ...args], { input: input === undefined ? undefined : JSON.stringify(input), encoding: 'utf8', }) if (child.status !== 0) throw new Error(child.stderr) return JSON.parse(child.stdout) } const catalogue = cli(['discover']) if (catalogue.protocolVersion !== '1.0.0') throw new Error('Unsupported protocol') const contracts = Object.fromEntries([ 'velocity-calculator', 'sprint-capacity-calculator', 'sprint-forecaster', ].map(slug => [slug, cli(['describe', slug])])) function calculate(slug, input) { // The CLI validates the entire schema; this shows how to use required fields. for (const field of contracts[slug].inputSchema.required) { if (!Object.hasOwn(input, field)) throw new Error(`Missing ${slug}.${field}`) } return cli(['run', slug, '--input', '-'], input) } const velocity = calculate('velocity-calculator', { rows: [{ committed: 24, completed: 22 }, { committed: 26, completed: 24 }], }) const capacity = calculate('sprint-capacity-calculator', { teamSize: 5, sprintDays: 10, hoursPerDay: 6, focusFactor: 70, ptoDays: 2, velocity: velocity.average, }) const forecast = calculate('sprint-forecaster', { remainingPoints: 120, velocity: velocity.average, velocityStdDev: velocity.standardDeviation, sprintLength: 2, startDate: '2026-10-05', }) console.log(JSON.stringify({ velocity, capacity, forecast }, null, 2)) JS ``` The sample gives mean velocity 23 points/sprint, standard deviation about 1.414, focused capacity 201.6 person-hours, suggested commitment 15.456 points and forecast dates 28 December 2026. Capacity's suggested commitment and the historical forecast serve different planning questions. Do not replace the forecast's historical velocity with the capacity estimate without explaining the changed assumption. P50/P90 are the existing normal-approximation heuristic, not measured probabilities or delivery guarantees. Point estimates apply to this team, not other teams. ## Output and error protocol `protocolVersion` and CLI `version` are `1.0.0`; `--version`, discovery, descriptions and errors include both. Successful `run` returns the **raw output object** on stdout, not a version envelope. Default output is JSON with a trailing newline. Markdown/SVG output is a raw document plus newline, selected only if the tool's `formats` advertises it. The CLI writes no files; redirection belongs to the caller. No progress logs appear on stdout. Success exits 0 with empty stderr. Failures exit 1 with empty stdout and exactly one JSON object on stderr: ```json { "protocolVersion": "1.0.0", "version": "1.0.0", "error": { "code": "INVALID_INPUT", "message": "$.velocity: must be at least 1", "details": [{ "path": "$.velocity", "message": "must be at least 1" }] } } ``` Codes are `INVALID_ARGUMENT`, `UNKNOWN_TOOL`, `UNSUPPORTED_FORMAT`, `INPUT_IO_ERROR`, `INVALID_JSON`, `INVALID_INPUT`, `COMPUTATION_ERROR` and `INTERNAL_ERROR`. Input errors give a field path when applicable. Messages are descriptive; branch on the code. JSON parsing errors never echo supplied text; IO errors do not echo private paths. Duplicate options are rejected. Malformed input should be corrected using the contract, not retried unchanged. For generators, keep placeholders until the team supplies facts. The MCP generator returns a token placeholder and does not connect to a server or execute its snippet. Actually using MCP still requires the account's token; keep credentials out of the free-tool input and generated artifact. ## Maintain the download With repository access and existing JavaScript build dependencies installed: ```sh bin/build-free-tools bin/build-free-tools --check node --test spec/cli/free_tools_agent.test.js ``` The build bundles the real CLI entry point and shared free-tool modules with the project's existing esbuild dependency. It copies this guide and generates the schema manifest/digest. It does not include Rails, browser controllers, application secrets or paid AI adapters. Commit the generated files whenever their source changes. CI checks freshness before running the isolated-artifact contracts and workflow tests. The blog authoring CLI remains a separate repository workflow.