Studio
Studio turns a written brief into an agent node. Its studio node delegates the build to a remote ATF Harness using the ATFGraph builder skills. One build uses one graph session, with recorded planning, approvals, file-tree digests and deployment runs. The Console presents the builder's transcript and approval gates. You can also operate Studio through the CLI or Python client.
What a build is
brief ──► studio.build ──► plan (Opus 5.5 or Fable 5.1 through the harness)
│ approval studio:plan:<label> ← you decide, optionally answering the plan's questions
▼
build turn: scaffold, verify against an isolated daemon, write studio/verification.json
│ approvals harness:<session>:<request> ← each shell command the builder wants to run
▼
review: file list, per-file diffs and tree digest from the harness workspace
│ approval studio:accept:<label>:<digest> ← accept the tree, by digest
▼
studio.deploy ──► plan (read-only) ──► approval studio:deploy:<label>:<digest> ──► the node App is deployed
The harness workspace is temporary. When you accept a file tree, Studio records its digest. Before deployment, studio.deploy fetches the files again and compares their digest with the accepted one. A mismatch stops deployment so an unreviewed tree cannot be substituted.
Running the studio node
Configure the studio node through its environment. It needs a reachable harness and a deployment identity; a laptop uses a named Databricks profile, while an App can use its service principal. These settings are not credential values inside the brief.
| variable | meaning |
|---|---|
ATFGRAPH_HARNESS_URL | the ATF Harness service, e.g. the atf-harness-pilot App URL |
ATFGRAPH_HARNESS_PROFILE | harness profile, default atfgraph-builder |
ATFGRAPH_HARNESS_WORKSPACE | one existing directory under the harness's workspace root, shared by every build |
ATFGRAPH_HARNESS_WORKSPACE_ROOT | instead: a root under which each build gets its own studio/<label> directory, created on the harness |
ATFGRAPH_HARNESS_EDGE_AUTH | databricks behind the Apps proxy (with ATFGRAPH_DATABRICKS_PROFILE on a laptop), else none |
ATFGRAPH_HARNESS_TOKEN | optional harness application token, sent as X-Atfhar-Token |
ATFGRAPH_HARNESS_MODEL | default model when the brief names none, e.g. databricks-claude-opus-5-5/databricks-claude-opus-5-5:high |
ATFGRAPH_STUDIO_TURN_TIMEOUT | seconds per harness turn, default 1800 |
ATFGRAPH_STUDIO_TRANSCRIPT | off stops recording the builder's transcript on the run (see "The transcript"); on by default since 0.3.16 |
ATFGRAPH_DEPLOY_PROFILE | Databricks CLI profile studio.deploy deploys under on a laptop (bundle engine); never chosen for you |
ATFGRAPH_DEPLOY_API_KEY | graph-server identity that mints node tokens for deployed nodes (an admin identity bound from the studio node's scope, e.g. --bind-secret ATFGRAPH_DEPLOY_API_KEY=deploy-api-key); default: the node's own key |
ATFGRAPH_STUDIO_WHEEL | the atfgraph wheel the deployed node bundles; optional when atfg is installed beside its wheel (<prefix>/share/atfgraph) |
python -m atfgraph.worker --module atfgraph.studio.node:app
atfg ls studio # build, continue, deploy, discard, doctor, schemas
atfg traverse studio.doctor --in '{}'
Call studio.doctor before a build. It checks reachability, readiness, protocol version and profile availability without starting a harness turn.
A build from the CLI
atfg traverse studio.build --new-session --in '{"brief": {
"brief": "A node with one skill reverse(text) that returns the reversed string and its length, and a traversal run(text) that validates the input and calls it.",
"label": "reverser",
"model": "databricks-claude-opus-5-5/databricks-claude-opus-5-5:high"
}}'
The run pauses when it needs approval. Decide the request from the Console's Runs page or from another program:
async with Client(server) as client:
for approval in await client.list_approvals():
if approval["operation_key"] == "studio:plan:reverser":
await client.decide_approval(approval["id"], "approved", {"answers": {"q1": "yes"}})
Put answers to planning questions in the approval response. Unanswered questions use the plan's defaults. Harness confirmations use approval keys shaped as harness:<session>:<request>. General harness progress carries identifiers; when Studio transcripts are enabled, shell approvals also include command text for review. The result includes plan, verification, review with files and diffs, reviewed_digest, the harness session ID and usage for both turns.
Deploy, continue, discard
atfg traverse studio.deploy --session <build session> --in '{"label": "reverser"}'
atfg traverse studio.continue --session <build session> --in '{"message": "Rename run to reverse_text"}'
atfg traverse studio.discard --session <build session> --in '{}'
deploy first presents the deployment engine's read-only plan in a studio:deploy:<label>:<digest> approval. Approval starts deployment using the studio node's Databricks identity. Inside an App, the API engine (--engine api) uses the App service principal, uploads the bundle under that principal's workspace home and bundles the SDK wheel used by Studio.
continue adds another turn to the same harness session after the previous turn finishes. Because that turn can edit files, it ends with a new review and studio:accept:<label>:<digest> approval. A later deployment uses the newly accepted digest. discard removes the harness session and its pairing while retaining the run records.
The brief
The StudioBrief type is in atfgraph.studio.schemas; studio.schemas returns its JSON Schema. Provide brief and label, with an optional model. attachments references files staged under brief/, such as specifications, documents, screenshots and sample payloads. mcp_servers describes a server's name, transport, address or command, tool names and the names of environment variables needed for authentication. secrets lists variable names and whether each is present, supplied now or created empty.
Keep credential values out of the brief. The builder writes .env.example; deployment resolves the secret names into the node's secret scope.
What gets recorded
| where | what |
|---|---|
| path of the build run | plan turn, build turn, the harness's events as progress events (identifiers only; streamed-token updates are not recorded since 0.3.17), the builder's transcript (below), three approvals |
| review | the file list, a bounded unified diff per file (entries[].diff, against the empty tree a build starts from) and the tree digest |
| checkpoints | studio:plan, studio:built, studio:review (per run) |
| session memory | the harness pairing and the accepted build (studio.review: label, digest, files) |
| run metadata | studio.label, studio.stage (planning, review, accepted, deploying, deployed, …) |
| usage | both turns' tokens (cache reads and writes count as input, reported separately too) and provider-reported cost; the harness's 0 for an unpriced route is recorded as unknown so the server's price table applies |
The transcript
With transcripts enabled, Studio records completed harness messages, including text, reasoning, tool arguments and output, plus tool-start and tool-end events. These become studio.transcript progress entries in the harness's message format. The Console renders them with the harness UI components; atfg path <run> and GET /traversers/{id}/event-log expose the raw records. Shell approvals include the command title and text so the reviewer can inspect the proposed action. Transcript recording has been enabled by default since 0.3.16.
Anyone authorized to read the run can read its recorded brief, commands and output. Before storage, Studio redacts credential-like environment values, Bearer and Basic headers, common key patterns (sk-…, dapi…, ghp_…, AKIA…, xox…) and PEM blocks. Each entry is capped at 64 KiB, retaining its beginning and end, and each run at 8 MiB. These patterns cannot recognize every secret format. Keep credentials out of the builder workspace and chat; supply deployment secret values through the server's session-secret mechanism.
Deleting a build removes transcript content from its event log, leaving deleted: true tombstones, and removes command text from shell approvals. The runs remain. Set ATFGRAPH_STUDIO_TRANSCRIPT=off for identifier-only recording; the Console then shows approval gates and explains that no transcript was saved. studio.schemas and studio.doctor report the active transcript setting.
Governing who may deploy
Build and deploy are separate capabilities. An access policy can therefore allow a principal to build while denying deployment, for example:
{"name": "studio-no-deploy", "label": "studio", "capability": "deploy", "principal": "builders", "effect": "deny"}
Install this policy with POST /api/v2/access/policies, as in the access-boundaries example. Deployment uses the studio node's service principal. Before its first deployment, grant that identity permission to create and deploy Apps, create and write secret scopes, and act as an administrator in the target graph namespace.
Limits and known gaps
- Remote limits: The harness profile selects tools and model. Remote calls do not accept a per-call dollar cap; use profile turn limits and node budget policies.
- Restart behavior: Harness sessions stored on disk survive harness restarts, App redeploys and idle stops. An interrupted active turn ends as
turn_aborted;continuestarts a new turn in that session. The in-memory event journal is lost, so cursor resumption can returnreset_requiredand require replay. Workspace files are lost on App redeploy or idle stop. - Review integrity: If workspace files disappear after acceptance, deployment refuses with "changed since review". Use
continueto rebuild and accept the new tree. An idle-stopped harness appears unreachable instudio.doctoruntil restarted. - Verification limits: The verification table is the builder's report. A harness without the ATFGraph runtime may skip daemon-backed checks and report
accepted_with_failures. A skipped check has not passed. Historical live evidence from 2026-09-27 showed a generated node,atfgraph-node-reverser-b4, answeringrun(text)after deployment; it does not establish that every build's checks passed. Review each build's table before deployment.