Agents

There are two different things an agent can do with your codebase.

It can write code in it — read some files, follow the conventions it finds, open a diff. Most tooling supports this, because it only requires the repository to be readable.

It can operate it — know what a change affects before making it, run the right jobs, read the result as data, tell you what is not production-ready and why. That requires the system to state what it is, in a form something other than its author can parse.

Putnami is built for the second one. This page is the contract that makes it possible. For the practical setup — assistant context files, prompt patterns — see Develop with AI assistants.


Orientation: read the system, not the files

When you run putnami init, the workspace gets shared assistant context: .AI/context.md (generated framework and workspace patterns, disposable), .AI/constraints.md (your durable rules), and thin per-tool entrypoints. Adding an extension later? putnami context generate rewrites the generated half.

That teaches an assistant your conventions. Two commands teach it your system.

putnami context map — where things are

putnami context map            # regenerate
putnami context map --print    # render to stdout, write nothing

The workspace orientation map, rebuilt from committed artifacts — project manifests, schema/openapi.json, schema/config.jsonschema.json, READMEs, and the docs tree. It answers "which project owns X", "what depends on Y", "where are the APIs, the config keys, the docs" without shell exploration.

It is byte-deterministic on an unchanged tree, lives gitignored under .putnami/context-map/, and is never committed. putnami build refreshes it automatically outside CI, so it does not go stale behind the code.

putnami context pack — how one project is composed

putnami context pack --project <project-id>

It writes one deterministic agent-context document per project to <project>/.gen/agent-context.json:

  • identity and graph — id, name, path, type, tags, languages, and the ids of dependencies and dependents;
  • composition roots — the application main, the describe entrypoint, and other roots, each with a path and a provenance tag;
  • capabilities, contracts, infra, migrations — references carrying a path and a sha256: digest, pointing at the committed artifacts;
  • representative sources — ordered ranges (path, startLine, endLine, a reason, a token estimate). Ranges only;
  • tests — the policy, referenced conformance packs, and fixture digests — or, when there are none, a machine-readable reason for their absence;
  • docs — adjacent documentation, each marked checked or unchecked;
  • config — a config-schema reference and refs-only hints about the operational surface;
  • provenance — the workspace revision, the generator, and the aggregation method.

Three properties are worth stating plainly, because they are what make the document safe to hand to a tool you don't control.

It aggregates by reference. Paths, digests, and line ranges. Never file content. The types have no slot for content, and the safety gate rejects any string long enough to look like it anyway.

It is ephemeral. It lives under the gitignored .gen/ root and is never committed — it embeds the workspace revision and content digests, so it would churn on every commit. Determinism is pinned byte-for-byte by tests at a fixed tree, not by committing the artifact.

Publication fails closed. Before a document can leave the workspace for an authorized index, a redaction gate runs and reports as hard errors: a reference to a sensitive path that is not flagged sensitive, anything resembling embedded content, any path that is absolute or escapes the workspace, and any duplicated reference. An empty document fails the gate, so it can never pass vacuously.

You can adjust the document, narrowly. <project>/schema/agent-context.overrides.json adds or removes representative-source and doc entries and force-flags paths as sensitive. It cannot override identity, capabilities, or provenance — those are framework-owned facts, and an author who could rewrite them could make the document lie.

In CI or pre-flight:

putnami context pack --check   # re-derives, exits non-zero on drift, writes nothing

The MCP server

putnami mcp install   # writes the putnami entry into .mcp.json, merge-aware
putnami mcp           # run the server over stdio (your client spawns this)

putnami init, putnami install, and putnami context generate register the entry already; mcp install is there to add it by hand or repair an edited one. Other servers in the file are preserved.

The server speaks JSON-RPC 2.0 on stdin/stdout, exits with the session, and exposes the workspace as typed tools instead of shell exploration:

Tools What they answer
Orient list_projects · describe_project · agent_context · workspace_map What is in this workspace, how is this project composed, where should I read first, which project owns X
Blast radius impacted · why_impacted · deps · find_owner · topo_sort What does my change affect, and by what path
Intent list_features · feature_context · list_specs · spec_context What was this built for, what were the non-goals, what did the team agree to
Execute run_jobs · get_diagnostics Run lint / test / build, then read every failure as file:line:col with severity and code

Plus the workspace://context resource, so a client that prefers resources over tool calls gets the same facts.

Every tool declares its own contract

Each tool carries a putnami.dev/contract block in its metadata: an access value (read or mutating), a readOnly flag, whether it supportsDryRun, and — when it mutates — a mutates list naming exactly what it touches.

run_jobs is the only mutating tool. Everything else is read-only. It runs jobs through the same planner and engine as the CLI, declares that it mutates the workspace and the cache, supports dryRun to return the selected dependency plan without starting a subprocess, and refuses long-lived serve mode and any job declared to mutate external systems.

An agent doesn't have to guess which call is safe. The tool says so.

Optional request provenance

Off by default. Set PUTNAMI_AGENT_IDENTITY=1 and explicitly set PUTNAMI_AGENT_MODEL in the MCP server environment, and requests carry bounded harness and model headers — so what an agent did is attributable after the fact, by the same principle that makes every other action in Putnami reviewable.


Blast radius before action

putnami lint,test,build --impacted

--impacted resolves the projects affected by the current changes against a baseline, transitively through the dependency graph. The baseline is resolved in a fixed order — workspace config, nearest configured epic branch, trunk, local main or master, then the upstream tracking ref — and never the current branch itself, so it cannot quietly resolve to "nothing changed".

When an agent needs to justify the result rather than trust it, why_impacted returns the shortest dependent path from the changed project to the impacted one, and find_owner maps a file path back to the project that owns it using the same logic.


A surface that parses the same way every time

putnami build --output=json
putnami test  --output=jsonl

Exit codes, output modes, the reserved global-flag registry, and the machine documents are the cli protocol — versioned, and validated by one conformance corpus executed from both the Go and the TypeScript implementation. An agent that learned the shape does not have to relearn it because a release changed a log line.

Every job also emits one JSONL event stream — logs, progress, phases, diagnostics, metrics, artifacts, results — so the agent watching a build and the human reading the log are parsing the same lines.


Verifying the work

Generating a change is the easy half. The useful half is telling whether it is safe.

putnami doctor --profile production

doctor is a read-only production-readiness preflight. It derives findings from committed manifests — incomplete capabilities, missing required config, invalid committed schemas, config shadowing — and grades them by deployment profile. Under --profile production a high or critical finding exits 2; dev and test stay advisory. Config values are never read or emitted, so running it in a pipeline leaks nothing.

Each check carries a remediation baked into the check itself, and the code taxonomy is frozen. Findings you have consciously accepted go into a committed doctor.waivers.json — a waiver is a reviewable decision in git, not a flag someone remembered to pass.

Alongside it: get_diagnostics re-reads the complete failure set from the last executed run without rerunning the work, conformance packs test declared capabilities against shared fixtures, and putnami context pack --check keeps the orientation document from going stale behind the code.


The documentation is part of the surface

Stable URL prefixes per section, Copy as Markdown on every page, and /llms.txt as a machine-readable index of the whole tree. The structure an agent reads is the structure you read.


What this deliberately does not do

  • The agent-context document is per project, and it references rather than embeds. It is an orientation artifact, not an index of your repository — an agent still reads the files it decides to read.
  • The MCP server runs workspace jobs. It does not deploy, does not reach external systems, and refuses jobs declared to do so.
  • Author overrides are narrow on purpose. If you could rewrite identity or capabilities, the document could lie, and every guarantee above would be worth nothing.
  • None of this makes an agent correct.

That last one matters. What the contract buys you is that an agent's actions are bounded, inspectable, and reversible — which is the precondition for letting one run at all.