diff --git a/.claude/skills/docs/watermark b/.claude/skills/docs/watermark
index 8afd61986..dbb3bc65d 100644
--- a/.claude/skills/docs/watermark
+++ b/.claude/skills/docs/watermark
@@ -1 +1 @@
-7ad164c45de64e7bafdadb26f519f6e0c8a00a42
+de29af0a30362c70c42f426e457e8a6d269534b2
diff --git a/docs/public/agents/outputs.mdx b/docs/public/agents/outputs.mdx
index 004c4f0e8..47bd1770e 100644
--- a/docs/public/agents/outputs.mdx
+++ b/docs/public/agents/outputs.mdx
@@ -277,6 +277,10 @@ Patterns are rooted at the sandbox working directory. `*` and `?` stay within on
Fabro prunes dependency, cache, and build directories including `.git`, `node_modules`, `target`, `.venv`, `.cache`, and `dist`.
+### Browse and download captures
+
+The Artifacts page groups captures by file path. Expand a file to see and download earlier versions. **Download all** creates a ZIP archive with the latest captured version of each path. Fabro uses stage order, retry number, and stage ID to choose the latest version, and it excludes captures from the graph's start and exit nodes.
+
## Observability
Outputs and artifacts appear in several observability surfaces:
@@ -285,6 +289,6 @@ Outputs and artifacts appear in several observability surfaces:
|---|---|
| `StageCompleted` event | `files_touched` list for the stage |
| `WorkflowRunCompleted` event | `artifact_count` -- total number of offloaded artifacts across the run |
-| Web UI | Run stage output, stage artifacts, and downloadable artifact files |
+| Web UI | Run stage output, artifact version history, individual downloads, and a ZIP of the latest files |
| [Preambles](/execution/context#preamble-construction) | File list and artifact pointer references for completed stages |
| Stage logs | `status.json` in each stage's run directory contains the full outcome including `files_touched` |
diff --git a/docs/public/agents/prompts.mdx b/docs/public/agents/prompts.mdx
index ff2c2fd4c..eed36c6d4 100644
--- a/docs/public/agents/prompts.mdx
+++ b/docs/public/agents/prompts.mdx
@@ -257,18 +257,19 @@ to load its instructions, then follow them.
-OpenAI and Gemini providers have their own system prompts with different identity text, tool guidance (e.g. `apply_patch` instead of `edit_file` for OpenAI), and coding conventions. The overall structure is the same.
+Fabro selects an agent profile for the model. Anthropic, Claude 5, OpenAI, GPT-5.6, Gemini, and Kimi profiles can use different identity text, tool names, tool guidance, and coding conventions. The overall system-prompt structure is the same.
### Project docs
-Fabro automatically discovers project instruction files by walking the directory hierarchy from the git root to the working directory. Which files are loaded depends on the provider:
+Fabro automatically discovers project instruction files by walking the directory hierarchy from the git root to the working directory. Which files are loaded depends on the agent profile:
-| Provider | Files |
+| Agent profile | Files |
|---|---|
-| Anthropic | `AGENTS.md`, `CLAUDE.md` |
-| OpenAI | `AGENTS.md`, `.codex/instructions.md` |
+| Anthropic and Claude 5 | `AGENTS.md`, `CLAUDE.md` |
+| OpenAI and GPT-5.6 | `AGENTS.md`, `.codex/instructions.md` |
| Gemini | `AGENTS.md`, `GEMINI.md` |
+| Kimi | `AGENTS.md` |
Files are loaded in directory order (root first, deepest last) with a total budget of 32KB. If the combined content exceeds this budget, later files are truncated.
diff --git a/docs/public/agents/subagents.mdx b/docs/public/agents/subagents.mdx
index 597bd96e3..1255cb8d0 100644
--- a/docs/public/agents/subagents.mdx
+++ b/docs/public/agents/subagents.mdx
@@ -16,9 +16,9 @@ Sub-agent management is exposed through four built-in tools:
| Tool | Description |
|---|---|
| `spawn_agent` | Create a new sub-agent with a task prompt |
-| `send_input` | Send follow-up input to a running sub-agent |
+| `send_input` | Send follow-up input to a running or completed sub-agent |
| `wait` | Block until a sub-agent completes and return its result |
-| `close_agent` | Cancel and remove a running sub-agent |
+| `close_agent` | Close a running or completed sub-agent |
These tools are registered automatically when the session starts. They inherit the parent's permissions.
@@ -32,6 +32,12 @@ Each sub-agent runs in its own session:
The parent can spawn multiple sub-agents and synchronize with them later.
+## Continue a completed session
+
+A completed sub-agent remains available until the parent closes it. Calling `send_input` starts another turn in the same child session, so the child keeps its conversation history. A message sent while the child is still running is queued for a safe turn boundary instead.
+
+Call `wait` again to receive the new turn's result. Call `close_agent` when the child is no longer needed; a closed child cannot accept more input.
+
## Depth limits
Sub-agents can themselves spawn sub-agents, creating a hierarchy. `max_subagent_depth` limits how deep that tree can grow. By default the depth limit is `1`.
diff --git a/docs/public/api-reference/overview.mdx b/docs/public/api-reference/overview.mdx
index bbb30e5e1..73c53edc3 100644
--- a/docs/public/api-reference/overview.mdx
+++ b/docs/public/api-reference/overview.mdx
@@ -128,6 +128,12 @@ Paginated responses include a `meta` object alongside the `data` array:
When `has_more` is `true`, increment the offset by the limit to fetch the next page.
+## Immutable workflow versions
+
+`POST /api/v1/workflow-versions` validates and stores a complete workflow package. The package contains an entrypoint, its text files, and exact IDs for child-workflow dependencies. Its SHA-256 ID is based on canonical content, so submitting the same package again returns the same ID.
+
+A package can contain at most 512 files and 512 workflow dependencies. Each file can contain at most 512 KiB, and the complete canonical package can contain at most 2 MiB. Invalid workflow content or missing dependencies return `422`.
+
## Versioning
The Fabro API is versioned under `/api/v1`. All versioned endpoints, including the OpenAPI document, live under that prefix. Future breaking changes can be introduced under a new versioned prefix while preserving existing clients.
diff --git a/docs/public/docs.json b/docs/public/docs.json
index 863662806..fedc54eca 100644
--- a/docs/public/docs.json
+++ b/docs/public/docs.json
@@ -187,6 +187,13 @@
"api-reference/client-sdks"
]
},
+ {
+ "group": "Workflow Versions",
+ "icon": "code-branch",
+ "pages": [
+ "POST /api/v1/workflow-versions"
+ ]
+ },
{
"group": "Runs",
"icon": "play",
@@ -202,6 +209,8 @@
"POST /api/v1/runs/{id}/cancel",
"POST /api/v1/runs/{id}/pause",
"POST /api/v1/runs/{id}/unpause",
+ "POST /api/v1/runs/{id}/pull_request",
+ "GET /api/v1/runs/{id}/pull_request/creation",
"GET /api/v1/runs/{id}/graph",
"GET /api/v1/runs/{id}/events"
]
@@ -220,6 +229,7 @@
"icon": "file-export",
"pages": [
"GET /api/v1/runs/{id}/artifacts",
+ "GET /api/v1/runs/{id}/artifacts/download",
"GET /api/v1/runs/{id}/billing",
{
"group": "Run Internals",
diff --git a/docs/public/execution/context.mdx b/docs/public/execution/context.mdx
index 19f9c1d2c..bc7e19d15 100644
--- a/docs/public/execution/context.mdx
+++ b/docs/public/execution/context.mdx
@@ -230,6 +230,12 @@ The preamble includes:
Internal keys (prefixed with `internal.`, `current`, `graph.`, `thread.`, `response.`) are excluded from preambles to avoid noise.
+### Large preamble values
+
+In fidelity modes that render context or completed-stage output, one value can contribute at most 8 KiB of serialized JSON inline. Fabro stores larger values as content-addressed blobs, materializes them as readable files, and puts the size, file path, and a 300-character preview in the preamble. The agent can read the file when it needs the full value.
+
+This prompt limit is separate from durable artifact offloading. If Fabro cannot demote a value, it logs a warning and keeps that value inline so the stage can continue.
+
## Artifact offloading
When a stage produces a large output (over 100KB of serialized JSON), Fabro stores the serialized bytes in a global content-addressed blob store and replaces the context value with a durable blob ref. Command output is always finalized into a blob ref after command completion, even when it is small or empty:
diff --git a/docs/public/execution/observability.mdx b/docs/public/execution/observability.mdx
index d2e694742..728b5dc0c 100644
--- a/docs/public/execution/observability.mdx
+++ b/docs/public/execution/observability.mdx
@@ -124,7 +124,7 @@ When running workflows through the API server, subscribe to the [run events endp
### Web UI
-The web frontend consumes the SSE stream automatically and shows stage progress, tool calls, command output, and human interaction as they happen. Use the stage `Thread` and `Debug` views for per-stage activity, or the run-level `Run Events` page when you need the full event stream with search and category filters. The `Run Events` page also includes a Waterfall view for comparing stage durations and inspecting timing details from hover popovers.
+The web frontend consumes the SSE stream automatically and shows stage progress, tool calls, command output, and human interaction as they happen. Use the stage `Chat` view for a readable conversation, `Thread` for the detailed agent transcript and disclosed provider reasoning, and `Debug` for raw stage events. Use the run-level `Run Events` page when you need the full event stream with search and category filters. The `Run Events` page also includes a Waterfall view for comparing stage durations and inspecting timing details from hover popovers.
diff --git a/docs/public/workflows/stages-and-nodes.mdx b/docs/public/workflows/stages-and-nodes.mdx
index d17db0d36..2c154635e 100644
--- a/docs/public/workflows/stages-and-nodes.mdx
+++ b/docs/public/workflows/stages-and-nodes.mdx
@@ -198,6 +198,8 @@ keeps the results in input order. The source lookup is flat:
`context.candidates` checks that exact key and then `candidates`; it does not
traverse nested objects.
+Each item can contribute up to 64 KiB of serialized JSON to its branch prompt. Fabro stores larger items as content-addressed blobs and replaces the inline item with its size, a readable file path, and a 300-character preview. The preview remains inside the untrusted-data fence, and the branch agent can read the file for the full item.
+
The template target must be an agent or prompt node, and nested `for_each` is
rejected. An empty source array succeeds with `parallel.results=[]` and skips
straight to `aggregate`. Missing, invalid, non-array, or over-long sources fail