Govern the fleet,
not the prompt.
Anyone can turn agents on. The question a platform owner has to answer is what happens next — how much they can spend, what they're allowed to touch, who says yes, and how you stop them. fastverk makes each of those a field on a resource you can read, diff, and audit.
| repo | fixes | blast radius | gate |
|---|---|---|---|
| rules_cc_cross | C3 · C6 | blast:rules_cc_cross://src | green BuildRun |
| plugin-depot | C6 | blast:plugin-depot://ui | green BuildRun |
| rules_lean | C3 | blast:rules_lean:* | serializes repo |
| …73 more | |||
maxTokens 2.1M / 3.0M concurrency4 leasesHeld4 Reason about the run, not the request.
Per-request guardrails are the wrong altitude for a fleet that will open forty pull requests before lunch.
The thing worth bounding isn't the individual call — it's the campaign: a batch of tasks under one spend ceiling, one concurrency cap, and one stop. That's a fan-out run, and it's a Kubernetes resource, so every control is a field you can read with kubectl, diff in git, and hand to an auditor.
Which matters more than it sounds. A guardrail expressed as a system prompt is a request. A guardrail expressed as an admission check is a property: the scheduler will not admit a task that would exceed the token budget, and there is no phrasing that talks it into doing so.
Two agents. One package. One of them waits.
A permissions model that says "this agent may write code" isn't a permissions model. This one is spatial: a task declares its Bazel affected-set, the scheduler leases each package before admitting it, and a task whose region is already held stays blocked with the reason on its status. Values illustrative.
- //src/toolchain
- //src/rules
- //tests/toolchain
- //src/rules
- //src/cache
conflict: lease blast:tbzl://src heldA toolchain, MODULE.bazel, or .bazelrc change can reach anything in the repo, so it takes blast:tbzl:* and serializes the whole repo rather than pretending to a narrow radius. Leases carry a TTL — a scheduler or agent that dies releases its region instead of wedging the fleet.
An agent's reach is exactly yours.
You don't provision an agent's permissions. It inherits yours, per call — and the inheritance is a reduction, never an expansion.
Forward
The host forwards the signed-in user's identity on every tool call. There is no shared service account to over-scope, and the forge's own record names a person rather than a bot.
Boundary
Each plugin's own MCP server is the authorization boundary. The host aggregates tools; it never decides what you may do. The owner of the capability does.
No static key
The model turn runs on Bedrock through the pod's IRSA role. There is no long-lived provider credential to leak, rotate, or find in a log.
Later turn
A write comes back flagged for confirmation as a preview. It fires only after you approve and the model re-calls it on a subsequent turn. It can't ask and act at once.
Configure the fleet, not each agent.
An AgentProfile is to an Agent what a WorkspaceConfig is to a DevWorkspace — one reusable template pinning the runtime, the model, the MCP servers every agent loads, its compute, and its environment. The last row is honest about what's declared but not yet enforced. Values illustrative.
| field | value | state |
|---|---|---|
| backend | claude-code | wired |
| model | claude-opus-4-8 | wired |
| mcpServers[] | agent-coord · meridian-mcp | wired |
| resources | 4 CPU · 8Gi | wired |
| defaultPlaybookRef | migrate-playbook | wired |
| env[].valueFrom | secretKeyRef — no literals | wired |
| tools[] | scopes the exposed tool set | declared |
Autonomy is earned per repo, not granted per org.
The eval harness drives the merge-gate loop deterministically through tool calls — no git, no model — so it measures whether the gate holds rather than how well an agent reasons. A nonzero false-merge rate exits nonzero: it's a CI gate, not a dashboard. Values illustrative.
| repo | runs | green merge | false merge | verdict |
|---|---|---|---|---|
| rules_cc_cross | 62 | 97.2% | 0.0% | graduated |
| aion/web | 51 | 91.4% | 0.0% | held — below the bar |
| plugin-forge | 23 | 96.1% | 2.1% | blocked — false merge ≠ 0 |
Every coordination step is a record, not a log line.
Spawn, claim, checkpoint, handoff, merge and human-prompt each append an AgentEvent to the durable agent-events stream. Live churn — presence, focus, claim state — stays on the KV where it belongs; the provenance lands where it can be replayed. Values illustrative.
Governing the agents is half of it.
The other half is where they work.
A governed agent still needs a machine, a toolchain, and a checkout — and so does the human reviewing its pull request. Give them the same one. We call it a verkspace: fastverk + workspace. The resource is still a DevWorkspace, the URL is still <name>.ws.fastverk.com, and the CLI is still fv ws create. The word is for what the thing becomes when the agents move in.
A verkspace is a workspace with the agents already in it — same layers, same identity, same remote execution.
A verkspace is a set of layers. Pick them.
The catalog is made of ToolLayer resources, so the gallery is add-a-CR-to-appear — apply another and it shows up, with no code change. Pick layers à la carte or pull one whole from a bundle, each pinned to a version, and save the result as a template your team and your agents launch from. Layers, versions, and image cost below are read from the shipped catalog.
ToolLayer CR and it appears here — no code change One environment. Not two.
The unit of control is the thing worth comparing.
What's built today — and what's next.
Straight about maturity, because a platform owner will ask. The controls that hold are reconciled today; the policy surface above them is the build ahead.
- The fan-out scheduler: a task is admitted only when its dependencies merged, its blast radius is free, it's within budget, and it's under the concurrency cap
- The kill switch — admits nothing, queued tasks go blocked, in-flight agents finish
- A token budget enforced at admission, summed from each checkpoint's usage
- Bazel blast-radius leases keyed
blast:<repo>:<pkg>, TTL-reclaimed if a scheduler or agent dies - A lease held until the build is green and the forge merges — green alone isn't merged
- A read-only launch plan: a dry run of a whole fan-out before any MR exists
- Profiles pinning backend, model, MCP servers, resources, playbook, and env from Secrets
- Human gate: raise → checkpoint → suspend → answer → resume from the checkpoint
- The durable agent-events stream, plus KV for claims and focus
- Faithful deputy — identity forwarded per tool call; Bedrock via IRSA, no static key
- Confirm-gated writes that can't fire in the same turn
- A false-merge rate that exits nonzero — the autonomy bar is a CI gate
- Workspaces: owner-scoped, template-driven, one wildcard, scale-to-zero at 30m idle
- An autonomy posture (gated vs open) and a conflict strategy — both in the CRD, no controller reads them yet
- A dollar spend ceiling — declared best-effort; only the token budget gates admission today
- Tool-set scoping from the profile — declared; the runner doesn't enforce it yet
- Recording who answered a human prompt and when — the fields exist, nothing writes them
- Four event kinds that are in the schema but not yet emitted
- Releasing idle leases on pause — today pause stops admission; leases hold
- Backends beyond the one the runner implements
- A console for run governance — the budget and the stop are fields, not yet a UI
- The compose gallery — the catalog, the endpoint, and the cart are built, not yet merged
Turn on the agents. Keep the stop button.
A budget, a blast-radius lease, a human gate, and a kill switch — on resources you can read. Then a verkspace to run it all in.