原始内容
Scribe
Work graph for AI agents. Scribe is a structured artifact store with native DAG support that lets AI coding assistants plan, track, and recall work across sessions -- beyond the limits of a single context window.
Quick Start
Container (recommended)
# podman or docker
podman run -d --name scribe \
-p 8080:8080 \
-v scribe-data:/data \
quay.io/dpopsuev/scribe:v1.5.2
Binary
go install github.com/dpopsuev/scribe/cmd/scribe@latest
scribe serve # stdio (Cursor, Claude Desktop)
scribe serve --transport http # Streamable HTTP on :8080
MCP Configuration
Cursor / Claude Desktop (stdio -- local binary):
{
"mcpServers": {
"scribe": {
"command": "scribe",
"args": ["serve"]
}
}
}
Cursor / Claude Desktop (HTTP -- container):
{
"mcpServers": {
"scribe": {
"url": "http://localhost:8080/?workspace=origami"
}
}
}
Agent runtime attachment (HTTP)
Prefer Streamable HTTP so multiple agents share one Scribe process. Stdio is fine for single-client local use.
scribe serve --transport http --addr :8080
| Concern | How |
|---|---|
| Liveness | GET /healthz |
| Scope | ?workspace=<scope> (comma-separated for multi-scope) |
| Auth | SCRIBE_AUTH_TOKEN → Bearer on MCP routes; /healthz open |
| Ingest | POST /api/v1/ingest (NDJSON; used by code-intel scanners) |
Claim ≈ assignee: artifact(action=claim, …) — TTL lease in Extra.claim. See help(query=claim).
Message stream: message_add / message_list (+ comment_* aliases) and cursor_mark / cursor_get. See help(query=message).
Librarian: mesh compaction operators (librarian, librarian_pass). Opt-in ticker: SCRIBE_LIBRARIAN_INTERVAL=24h (Go duration or hours; empty/0 = off). See help(query=librarian).
Sessions: agent.session / agent.turn when record_session is on — not the same as MCP HTTP session IDs.
Workflow
Scribe is designed for natural language. You talk to your agent, and it builds the work graph behind the scenes.
You: I want authentication and rate limiting for v1.0.
Agent: There's already a spec for rate limiting. I've created a spec for auth. What's your goal for today?
You: I need to reinforce security — we found a token leak vulnerability.
Agent: I've run an audit and created a goal for Security Reinforcement. Filed
BUG-1: Token leak. Would you like a campaign as well?
You: Yes.
Agent: Campaign ready. Here's the audit and brief — 3 tasks, spec for the auth fix, bug for the leak, topo sort shows the execution order. Auth fix first, then rate limiting, then leak patch.
You: Execute the campaign.
Agent: (works through tasks) Security Reinforcement campaign complete. 3 tasks closed, code committed, all tests green.
The Problem
LLM context windows are finite. A coding agent can hold ~100K tokens in working memory. When a session ends, everything it learned -- goals, decisions, dependencies, progress -- evaporates.
This creates three failure modes:
- Amnesia. The agent re-discovers the same codebase from scratch every session.
- Drift. Multi-session work loses coherence because there's no shared record of what was decided and why.
- Fragmentation. Plans scattered across chat logs, markdown files, and issue trackers can't be queried or traversed as a graph.
Scribe solves this by giving agents a structured, persistent memory they can read and write through MCP tools -- a place to store campaigns, goals, specs, tasks, bugs, and their relationships in a queryable DAG.
Core Concepts
| Concept | What it is |
|---|---|
| Artifact | The universal record. Everything is an artifact with a kind, status, scope, and auto-generated ID (e.g. TASK-2026-042). |
| Kind | The type of artifact. Canonical kinds: goal, task, spec, bug, campaign, template, need, ref, doc, decision, config, mirror. Enforced by schema validation. |
| Task | The primary unit of work. A task carries a goal statement, design sections, and dependency edges. Tasks implement specs and bugs. |
| Spec | A specification: the what and why. Defines acceptance criteria. Tasks implement specs. |
| Bug | A defect record. Like a spec, a bug is resolved by a task that implements it. |
| Goal | The north-star artifact for a scope. Setting a goal auto-creates a root delivery artifact and archives any previous goal. |
| Status | Lifecycle state: draft → active → complete / dismissed. Also: current (goals), retired, archived. |
| Scope | The project or repository an artifact belongs to (e.g. locus, origami). Enables multi-project planning from a single Scribe instance. |
| Section | A named text block attached to an artifact. Use for design notes, mermaid diagrams, acceptance criteria, or any structured content. |
| Campaign | Cross-project mission container. Groups goals, specs, and tasks under a theme (e.g. "v1 stabilization"). |
| Template | Meta-artifact (artifact about artifacts). Defines required sections and guidance for a kind. Artifacts link to templates via satisfies. |
| Need | A requirement or capability gap. Justifies goals and specs. |
| Config | Runtime configuration artifact. Sections are key-value pairs with cascading resolution (scoped > global). |
| Edge | A directed relationship: parent_of, depends_on, follows, justifies, implements, documents, satisfies. Edges form a DAG that agents can traverse. |
Artifact Relationships
graph LR
subgraph "Organizes Work"
CAMPAIGN["campaign"]
GOAL["goal"]
end
subgraph "Defines Work"
SPEC["spec"]
BUG["bug"]
NEED["need"]
end
subgraph "Does Work"
TASK["task"]
end
TEMPLATE["template"]
CAMPAIGN -- parent_of --> GOAL
GOAL -- parent_of --> TASK
GOAL -- parent_of --> SPEC
GOAL -- parent_of --> BUG
TASK -- implements --> SPEC
TASK -- implements --> BUG
TASK -- depends_on --> TASK
TASK -. follows .-> TASK
NEED -. justifies .-> SPEC
CAMPAIGN -. satisfies .-> TEMPLATE
GOAL -. satisfies .-> TEMPLATE
TASK -. satisfies .-> TEMPLATE
SPEC -. satisfies .-> TEMPLATE
BUG -. satisfies .-> TEMPLATE
Campaigns are mission containers that group goals. Goals are north-star artifacts that parent specs, tasks, and bugs. Specs and bugs define what needs to happen. Tasks implement specs and resolve bugs. depends_on edges enforce execution order; follows edges suggest ROI order. The detect admin tool warns when a task has no spec/bug link, or when a spec/bug has no implementing task.
Example Artifact Graph
graph TD
CMP["SCR-CMP-1\nv1.0 Campaign\n(active)"]
GOAL["SCR-GOL-1\nv1.0 Release\n(current)"]
CMP -->|parent_of| GOAL
SPEC["SCR-SPC-1\nAuth Spec\n(complete)"]
GOAL -->|parent_of| SPEC
BUG["SCR-BUG-1\nToken Leak\n(open)"]
GOAL -->|parent_of| BUG
TSK1["SCR-TSK-1\nImplement Auth\n(complete)"]
TSK1 -.->|implements| SPEC
GOAL -->|parent_of| TSK1
TSK2["SCR-TSK-2\nRate Limiting\n(active)"]
TSK2 -.->|depends_on| TSK1
GOAL -->|parent_of| TSK2
TSK3["SCR-TSK-3\nFix Token Leak\n(draft)"]
TSK3 -.->|implements| BUG
GOAL -->|parent_of| TSK3
Solid arrows are parent_of edges (tree structure). Dashed arrows are implements, depends_on, or follows edges (semantics). The agent uses graph next to find the highest-priority unblocked task whose dependencies are all complete.
Architecture
Diagrams generated by Locus (
locus diagram --theme natural). Components colored by health: green = healthy, yellow = sick (fan-in >= 3, churn >= 8), red = fatal.
Dependency Graph
locus diagram /path/to/scribe --type dependency --theme natural
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#F7FAFC', 'primaryTextColor': '#2D3748', 'primaryBorderColor': '#4A90D9', 'lineColor': '#4A90D9', 'background': '#FFFFFF', 'fontSize': '14px'}}}%%
graph TD
classDef boundary fill:#FFFFFF,stroke:#718096,color:#2D3748
classDef component fill:#F7FAFC,stroke:#4A90D9,color:#2D3748
classDef edge stroke:#4A90D9
classDef entry fill:#4A90D9,stroke:#4A90D9,color:#FFFFFF
classDef fatal fill:#E53E3E,stroke:#E53E3E,color:#FFFFFF
classDef healthy fill:#38A169,stroke:#38A169,color:#FFFFFF
classDef sick fill:#D69E2E,stroke:#D69E2E,color:#FFFFFF
classDef violation_edge stroke:#E53E3E
cmd_scribe["cmd/scribe [churn:12]"]:::entry
config["config [churn:6]"]:::healthy
directive["directive [churn:6]"]:::healthy
keygen["keygen [churn:2]"]:::healthy
lifecycle["lifecycle [churn:7]"]:::healthy
mcp["mcp [churn:20]"]:::healthy
mcpclient["mcpclient [churn:1]"]:::healthy
model["model [churn:9]"]:::sick
protocol["protocol [churn:14]"]:::sick
render["render [churn:1]"]:::healthy
store["store [churn:13]"]:::sick
web["web [churn:6]"]:::healthy
cmd_scribe -->|"13"| config
cmd_scribe -->|"7"| directive
cmd_scribe -->|"2"| mcp
cmd_scribe -->|"6"| mcpclient
cmd_scribe -->|"18"| model
cmd_scribe -->|"90"| protocol
cmd_scribe -->|"3"| render
cmd_scribe -->|"6"| store
cmd_scribe -->|"1"| web
config -->|"2"| model
config -->|"5"| protocol
config -->|"1"| store
lifecycle -->|"6"| model
lifecycle -->|"6"| store
mcp -->|"8"| directive
mcp -->|"6"| mcpclient
mcp -->|"9"| model
mcp -->|"88"| protocol
mcp -->|"3"| render
mcp -->|"1"| store
protocol -->|"1"| keygen
protocol -->|"5"| lifecycle
protocol -->|"57"| model
protocol -->|"21"| store
render -->|"24"| model
store -->|"40"| model
web -->|"2"| model
web -->|"12"| protocol
Layer Diagram
locus diagram /path/to/scribe --type layers --theme natural
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#F7FAFC', 'primaryTextColor': '#2D3748', 'primaryBorderColor': '#4A90D9', 'lineColor': '#4A90D9', 'background': '#FFFFFF', 'fontSize': '14px'}}}%%
block-beta
columns 1
block:layer_0["Layer 0"]
cmd_scribe["cmd/scribe"]
end
columns 3
block:layer_1["Layer 1"]
config["config"]
mcp["mcp"]
web["web"]
end
columns 4
block:layer_2["Layer 2"]
directive["directive"]
mcpclient["mcpclient"]
protocol["protocol"]
render["render"]
end
columns 2
block:layer_3["Layer 3"]
keygen["keygen"]
lifecycle["lifecycle"]
end
columns 1
block:layer_4["Layer 4"]
store["store"]
end
columns 1
block:layer_5["Layer 5"]
model["model"]
end
Packages
| Package | LOC | Churn | Role |
|---|---|---|---|
cmd/scribe |
1880 | 19 | CLI entry point. Every MCP tool has a CLI equivalent. Capsule and seed-dir commands. |
mcp |
3215 | 44 | MCP server. Handlers for artifact, graph, and admin tools. Bulk ops, diff, top-N, impact. |
protocol |
4939 | 38 | All business logic. Capsule export/import, seed, config resolution, template conformance. |
model |
1048 | 25 | Data model: Artifact, Section, Edge, Filter, Schema, IDConfig. |
store |
2656 | 30 | Persistence interface + SQLite. Snapshots with pluggable backend. |
render |
281 | 2 | Markdown and table formatters for CLI and MCP output. |
config |
281 | 12 | Configuration loading, workspace definitions, seed_dir. |
directive |
119 | 6 | MCP tool registry and input validation. |
keygen |
214 | 2 | Auto-generated ID sequences per artifact kind. |
web |
371 | 7 | Web UI for artifact browsing and sprint boards. |
Storage
Single SQLite database (CGo-free via modernc.org/sqlite). Tables:
- artifacts -- UID primary key (crypto/rand hex), human-readable ID as unique index with auto-rename on collision. JSON for arrays/maps.
- edges -- directed graph:
(from, to, relation)with a unique constraint. - sequences / scoped_sequences -- auto-increment counters with collision checks.
Snapshots: automatic periodic backups with pluggable backend (local filesystem, future S3). Restore with pre-restore backup via admin snapshot restore.
Default location: ~/.scribe/scribe.sqlite (binary) or /data/scribe.sqlite (container).
Data Model
Every artifact carries:
- Identity: auto-generated ID (
PREFIX-YYYY-SEQ), kind, scope - Content: title, goal statement, named sections (arbitrary text blocks)
- Graph: parent, depends_on edges, typed links (justifies, implements, documents)
- Lifecycle: status, priority, sprint assignment, labels, timestamps
- Extension:
extramap for domain-specific key-value pairs (reminders, custom fields)
The vocabulary is enforced: unknown kinds are rejected with a hint to register them via scribe vocab add. Unknown fields go into extra.
MCP Tools
| Tool | Description |
|---|---|
artifact |
Create, read, update, and manage work artifacts. Actions: create, batch_create, clone, get (bulk via ids, section_filter), list (compact fields, count, group_by, top-N ranking), set, update (patch map), archive, attach_section, get_section, detach_section, diff. Template auto-linking with cascading resolution. |
graph |
Navigate and modify artifact relationships. Actions: tree, briefing, topo_sort, link, unlink, bulk_link, bulk_unlink, move (re-parent), replace (swap target), impact (downstream analysis). Relations: parent_of, depends_on, follows, justifies, implements, documents, satisfies. |
admin |
System administration and monitoring. Actions: motd, changelog, dashboard, snapshot (create/list/diff/restore), set_goal, vacuum, detect, lint, check, seed, transfer_scope (with dry_run), set_scope_labels, list_scope_labels. |
Configuration
Scribe works with zero configuration. For customization, create a scribe.yaml:
# scribe.yaml
db: ~/.scribe/scribe.sqlite
transport: stdio
addr: ":8080"
scopes:
- myproject
vocabulary:
kinds:
- goal
- sprint
- task
- spec
- bug
# add your own via: scribe vocab add <kind>
schema:
kinds:
goal: { prefix: GOAL }
sprint: { prefix: SPR }
task: { prefix: TASK }
spec: { prefix: SPE }
bug: { prefix: BUG }
campaign: { prefix: CON }
template: { prefix: TPL }
need: { prefix: NED }
statuses:
- draft
- active
- current
- complete
- dismissed
- archived
guards:
archived_readonly: true
completion_requires_children_complete: true
auto_archive_goal_on_justify_complete: true
delete_requires_archived: true
auto_complete_parent_on_children_terminal: true
auto_activate_next_draft_sprint: true
workspaces:
origami: [origami, asterisk, achilles]
sidecar: [scribe, locus, lex, limes]
Resolution order: --config flag > $SCRIBE_CONFIG > ./scribe.yaml > $SCRIBE_ROOT/scribe.yaml > ~/.scribe/scribe.yaml > built-in defaults.
Override chain: CLI flags > environment variables > config file > defaults.
Workspace connections (HTTP): Add ?workspace=origami to the MCP URL to scope a connection to specific scopes.
For containers, mount a config file at /data/scribe.yaml:
podman run -d --name scribe \
-p 8080:8080 \
-v scribe-data:/data \
-v ./scribe.yaml:/data/scribe.yaml \
quay.io/dpopsuev/scribe:v1.5.2
Environment Variables
| Variable | Default | Description |
|---|---|---|
SCRIBE_ROOT |
~/.scribe |
Storage root; sets default DB and config paths |
SCRIBE_DB |
$SCRIBE_ROOT/scribe.sqlite |
Database path (overrides SCRIBE_ROOT) |
SCRIBE_TRANSPORT |
stdio |
Transport: stdio or http |
SCRIBE_ADDR |
:8080 |
Listen address (HTTP transport only) |
SCRIBE_CONFIG |
./scribe.yaml or $SCRIBE_ROOT/scribe.yaml |
Path to config file (first found wins) |
SCRIBE_LOG_LEVEL |
info |
Log level: debug, info, warn, error. JSON to stderr. |
SCRIBE_WORKSPACE |
— | Workspace name for stdio transport (resolves scopes from config). |
SCRIBE_AUTH_TOKEN |
— | If set, MCP HTTP routes require Authorization: Bearer …. /healthz stays open. |
SCRIBE_MCP_STATELESS |
true |
HTTP: accept stale Mcp-Session-Id after restart. Set 0 for sticky sessions. |
License
MIT