Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions data/runtime_stats.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
schema_version: 1
last_generated_utc: '2026-05-20T20:26:34Z'
generator_revision: f2e9a66b5
last_generated_utc: '2026-05-20T21:40:55Z'
generator_revision: 0fafe591c
stats:
tests:
raw: 32136
raw: 32241
rounded: 32000
display: 32,000+
mem0_stars:
Expand Down
1 change: 1 addition & 0 deletions docs/DESIGN_SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ The design specification has been split into focused documentation pages for bet
| [Memory Organizational](design/memory-organizational.md) | Shared Knowledge | Company-wide policies, ADRs, OrgMemoryBackend protocol, research directions |
| [Memory Operational](design/memory-operational.md) | Operational Data Persistence | PersistenceBackend protocol, per-entity repositories, SQLite + Postgres, multi-tenancy, invariants |
| [Memory Learning](design/memory-learning.md) | Learning + Injection | Procedural memory auto-gen, capture / pruning / propagation strategies, injection strategies, MemoryService |
| [Living Documentation](design/living-documentation.md) | Per-project wiki + RAG | Dual-purpose living docs (status reports, deliverables, knowledge notes): git-versioned workspace store, PROJECT_DOC RAG namespace, agent write tools + MCP, dashboard wiki |
| [Persistence](design/persistence.md) | Persistence | Repository protocol, SQLite/Postgres backends, time-series tables, TimescaleDB, migrations |
| [Multi-Agent Memory Consistency](design/memory-consistency.md) | Consistency Model | Append-only writes, MVCC snapshot reads, conflict handling, deployment rollout |
| [Semantic Ontology](design/ontology.md) | Entity Definitions, Versioning, Drift | Shared vocabulary, decorator, backend, bootstrap, drift detection |
Expand Down
1 change: 1 addition & 0 deletions docs/decisions/0001-repository-protocol-consolidation.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ compose any generic category and are documented at the end as "bespoke per D7".
| 46 | CeremonySchedulerStateRepository | persistence/ | IdKeyed | `load_all` | WP-1 restart safety: hydrate counters/fired-once flags on sprint activation; perf bulk read on cold start |
| 47 | MeetingCooldownRepository | persistence/ | IdKeyed | `load_all` | WP-1 restart safety: hydrate cooldown timestamps on scheduler start; perf bulk read on cold start |
| 48 | TrackedContainerRepository | persistence/ | IdKeyed | `load_all` | WP-1 restart safety: enumerate sandbox containers for reconciliation on subsystem start |
| 49 | DocsRepository | persistence/docs_protocol.py | IdKeyed (composite) + FilteredQuery | -- | Living-doc metadata; composite `(project_id, slug)` key, filter by doc_type / tag / updated_since |

### Bespoke-Only Protocols (No Generic Composition)

Expand Down
190 changes: 190 additions & 0 deletions docs/design/living-documentation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
# Living Documentation

Per-project documentation that is **dual-purpose**: human-browsable as a
wiki in the dashboard AND chunked + embedded into the existing
hybrid-retrieval memory pipeline as a first-class RAG namespace. Status
reports and deliverables land here as living documents, versioned in
the project git workspace.

See also: [memory.md](memory.md), [engine.md](engine.md),
[page-structure.md](page-structure.md).

## Goal

The org documents itself. A status report written by an agent on task
T1 is browsable in the dashboard immediately AND is retrieved by an
agent on task T2 days later via the standard memory search path.

## Surface

```text
src/synthorg/docs_engine/
models.py - LivingDocument + DocBlock discriminated union
serializer.py - deterministic JSON on disk (sorted keys, indent=2)
chunker.py - block-aware deterministic chunker
indexer.py - PROJECT_DOC entries with project + slug + type tags
writer.py - serialise -> workspace -> commit on docs branch
slug.py - kebab-case derivation with collision suffix
service.py - DocsService: write_doc, read_doc, list, search, history
retrieval_facade.py - ProjectAwareMemoryFacade (TaskGroup fan-out)
factory.py - build_docs_service(...) -> DocsRuntime
tool_factory.py - DocsToolFactory: per-task agent tools
constants.py - chunk size, branch name, namespace, ...
errors.py - DocNotFoundError, DocVersionConflictError, ...
```

## Storage model

Each living doc is one JSON file at
``<workspace>/.synthorg/docs/<doc_type>/<slug>.json``. The bytes are
deterministic: identical doc state always produces identical bytes, so
git diffs stay localised when content changes and disappear entirely
on re-writes that change nothing.

```mermaid
flowchart LR
Agent[Agent on task T1] -->|WriteLivingDocTool| Service[DocsService]
Service -->|serialize| Writer[DocWriter]
Writer -->|git add+commit| Branch[synthorg/docs branch]
Branch -->|push| Backend[GitBackend]
Service -->|chunk| Chunker[DocChunker]
Chunker --> Indexer[DocIndexer]
Indexer -->|MemoryBackend.store| Memory[(PROJECT_DOC entries)]
```

## Doc types (taxonomy)

`DocType` is a `StrEnum` in `synthorg.core.enums`:

| Type | Purpose |
|---|---|
| `status_report` | Periodic or per-task summary an agent writes for progress and decisions. |
| `deliverable` | The artifact the studio is producing (PRD, design doc, research memo). Iteratively edited. |
| `knowledge_note` | Freeform knowledge captured by an agent during work. |

All three share storage, chunking, and indexing. The type drives wiki
filtering and renderer affordances only.

## Block schema

`LivingDocument.body` is a `tuple[DocBlock, ...]` where `DocBlock` is a
discriminated union (`block_kind` literal). Day-one block kinds:

- `HeadingBlock(level=1..6, text)`
- `ProseBlock(text)` (plain text day one; no markdown)
- `BulletListBlock(items=(...))`
- `CodeBlock(language?, code)`
- `DecisionBlock(decision, rationale)`
- `MetricBlock(name, value, unit?)`
- `LinkBlock(label, url)`

Every block carries a stable `block_id` UUID so re-orders produce
meaningful git diffs even though the JSON encoding reshuffles bytes.

## RAG namespace

`MemoryCategory.PROJECT_DOC` is a new top-level memory category. Every
indexed chunk lives in one fixed namespace `project_docs`; per-project
scoping uses tags:

| Tag prefix | Purpose |
|---|---|
| `project:<id>` | Project scope. The retrieval facade filters by this. |
| `doc_slug:<slug>` | Identifies the source doc. Used by the indexer to delete prior chunks idempotently. |
| `doc_type:<value>` | Doc taxonomy bucket. Lets search hits expose the type without a per-hit repository lookup. |

Chunks store under the synthetic `SYSTEM_DOCS_AGENT_ID = "_system:docs"`
agent ID so the per-agent storage abstraction stays intact.

## Retrieval paths

Two paths, both first-class:

1. **Transparent** (`ProjectAwareMemoryFacade`): when an agent on
project P calls `memory.retrieve(agent_id, query)`, the facade
fans out via `asyncio.TaskGroup` to the agent's own memories AND to
`PROJECT_DOC` entries scoped to P. Results merge by descending
relevance score. Project docs become first-class RAG members
without any special-casing in agent code.
2. **Explicit** (`SearchLivingDocsTool`, `DocsService.search`): an
agent calls the docs-only search tool when it wants a doc-specific
query (e.g. "list deliverables tagged checkout").

## Versioning

Each doc write goes through the existing per-project push queue (#1974)
to commit on a dedicated `synthorg/docs` branch. History equals
`git log`. Persistence stores only the latest commit pointer + the SHA
last seen by the indexer:

```text
project_docs(project_id, slug, doc_type, title, tags,
head_commit_sha,
last_indexed_commit_sha, -- nullable; gaps replayed on boot
created_at, updated_at)
```

A gap between `head_commit_sha` and `last_indexed_commit_sha` indicates
chunks that were committed but never reached the memory backend (e.g.
transient outage). A boot-time replay job re-indexes those commits;
the indexer is idempotent because prior chunks are deleted by the
`doc_slug:<slug>` tag before fresh ones are stored.

## Slug policy

Slugs are derived from the title: `kebab(title)`. On collision against
existing slugs in the same project + doc_type bucket, the service
appends `-2`, `-3`, ... Agents never supply slugs via the write tool
(decision 9 in the plan). The slug + project_id is the composite
primary key on the metadata row.

## API surface

REST (read-only, web dashboard):

| Method | Path | Returns |
|---|---|---|
| `GET` | `/projects/{project_id}/docs` | Paginated `DocSummary[]` (recency-first) |
| `GET` | `/projects/{project_id}/docs/{slug}` | `LivingDocument` |
| `GET` | `/projects/{project_id}/docs/{slug}/history` | `DocVersion[]` from git log |
| `GET` | `/projects/{project_id}/docs/search?q=...` | `DocSearchHit[]` ordered by relevance |

Agent tools (in-process; per-task binding):

- `WriteLivingDocTool` (`docs:write` action type, admin via TrustService)
- `SearchLivingDocsTool` (`memory:read` action type)

MCP handlers (operator-driven, via `synthorg.meta.mcp.domains.docs`):

- `docs:write` (admin capability)
- `docs:get`, `docs:list`, `docs:search`, `docs:history` (read capability)

## Web dashboard

Page lives at `web/src/pages/ProjectDocsPage.tsx`, route
`/projects/:projectId/docs[/slug]`. Layout: doc list sidebar +
`DocViewer` main area. `DocBlockRenderer` has one renderer per block
kind, all using design tokens (no hardcoded hex / pixel spacing).
Untrusted-content wrap (SEC-1) is applied at the agent retrieval
boundary, not on storage.

## Acceptance (#1976)

The org produces a status report and a deliverable doc; both are
browsable in the dashboard AND retrievable by an agent via memory on
a later task. Validated end-to-end by
`tests/integration/docs_engine/test_service_round_trip.py`:

- `test_write_then_read_returns_same_doc`
- `test_write_commits_on_docs_branch`
- `test_search_returns_indexed_doc`
- `test_facade_surfaces_doc_for_other_agent` (decision 8a, the
"another agent on a later task" path)
- `test_reindex_replaces_prior_chunks`
- `test_versioned_read_via_git_show`

Plus the per-component unit suite under `tests/unit/docs_engine/`
(39 tests covering models, serializer, chunker, indexer, slug,
PROJECT_DOC category) and the dual-backend persistence conformance
under `tests/conformance/persistence/test_docs_repository.py`
(24 SQLite + Postgres tests).
4 changes: 3 additions & 1 deletion docs/design/memory.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ consolidation / retention pipeline.
* [Shared Organizational Memory](memory-organizational.md): company-wide knowledge (policies, ADRs, procedures) behind `OrgMemoryBackend`.
* [Operational Data Persistence](memory-operational.md): `PersistenceBackend` protocol, per-entity repositories, SQLite + Postgres backends, schema strategy, multi-tenancy, database-enforced invariants.
* [Memory Learning and Injection](memory-learning.md): procedural memory auto-generation (failure + success capture), cross-agent skill pool, injection strategies (context / tool-based / self-editing), `MemoryService` REST + MCP entry point.
* [Living Documentation](living-documentation.md): per-project documentation as a dual-purpose wiki + RAG namespace, integrated via the `PROJECT_DOC` memory category and `ProjectAwareMemoryFacade`.

---

Expand All @@ -51,6 +52,7 @@ and all access flows through the [`MemoryBackend`](#memorybackend-protocol) prot
| **Semantic** | Knowledge | Long-term | "This project uses Litestar with aiosqlite" |
| **Procedural** | Skills/patterns | Long-term | "Code reviews require 2 approvals here" |
| **Social** | Relationships | Long-term | "The QA lead prefers detailed test plans" |
| **Project doc** | Project-scoped living documentation | Long-term | "Q3 status report: checkout flow shipped, retention trending up" |

---

Expand Down Expand Up @@ -89,7 +91,7 @@ config.

| Enum | Values | Purpose |
|------|--------|---------|
| `MemoryCategory` | WORKING, EPISODIC, SEMANTIC, PROCEDURAL, SOCIAL | Memory type categories |
| `MemoryCategory` | WORKING, EPISODIC, SEMANTIC, PROCEDURAL, SOCIAL, PROJECT_DOC | Memory type categories |
Comment thread
coderabbitai[bot] marked this conversation as resolved.
| `MemoryLevel` | PERSISTENT, PROJECT, SESSION, NONE | Persistence level per agent |
| `ConsolidationInterval` | HOURLY, DAILY, WEEKLY, NEVER | How often old memories are compressed |

Expand Down
6 changes: 5 additions & 1 deletion docs/design/page-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ Project list with card grid, search, and status filter. "Create Project" button

Detail page (`/projects/{projectId}`) shows project header with status badge and key metrics, team section with avatar grid and lead badge, and a linked task list with status indicators.

Living-documentation page (`/projects/{projectId}/docs`, optional `/{slug}`) is the per-project wiki: a two-column layout with a doc-list sidebar (type-filter chips for status report / deliverable / knowledge note) and a `DocViewer` that renders a `LivingDocument`'s typed blocks one renderer per block kind. Docs are written by agents (tools + MCP), git-versioned on the `synthorg/docs` branch, and chunked into the `PROJECT_DOC` memory namespace for retrieval. See [Living Documentation](living-documentation.md).

**Features**:

- **Card grid**: responsive 3/2/1 column layout with hover effects, stagger animation
Expand All @@ -103,7 +105,7 @@ Detail page (`/projects/{projectId}`) shows project header with status badge and
- **Team section**: avatar grid with links to agent detail pages, lead badge
- **Task list**: linked tasks with status indicators and assignee display

**API endpoints**: `GET /projects`, `GET /projects/{id}`, `POST /projects`, `DELETE /projects/{id}`
**API endpoints**: `GET /projects`, `GET /projects/{id}`, `POST /projects`, `DELETE /projects/{id}`, `GET /projects/{id}/docs`, `GET /projects/{id}/docs/{slug}`, `GET /projects/{id}/docs/{slug}/history`, `GET /projects/{id}/docs/search`
**WS channels**: `projects` (emits `project.created`, `project.deleted`), `tasks`

#### Artifacts (`/artifacts`)
Expand Down Expand Up @@ -379,6 +381,8 @@ Sidebar layout (220px expanded, 56px icon rail):
| `/agents/:agentName` | Agent detail | Full page with scrollable sections |
| `/projects` | Projects | List with search/filter |
| `/projects/:projectId` | Project detail | Full page with team, tasks |
| `/projects/:projectId/docs` | Living docs | Per-project wiki: doc list + viewer (status reports, deliverables, knowledge notes) |
| `/projects/:projectId/docs/:slug` | Living doc detail | Full doc view with typed-block rendering |
| `/workflows` | Workflows | Card grid list with search, type filter, create (blank or from blueprint)/duplicate/delete |
| `/workflows/editor` | Workflow Editor | Visual DAG editor for workflow definitions (8 node types incl. subworkflow, 4 edge types, YAML preview, validation, version history with diff/rollback) |
| `/subworkflows` | Subworkflows | Registry card grid with search, I/O signature, version count, detail drawer with parents and delete |
Expand Down
9 changes: 9 additions & 0 deletions scripts/_ghost_wiring_manifest.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,12 @@ ENFORCED CostForecaster #1982 -- constructed in api/app.py::_wire_cost_dial_serv
ENFORCED ForecastGate #1982 -- constructed in engine/pipeline/entry/boot.py::_forecast_gate_for and passed through build_work_entry_adapter as the work_pipeline seam; consulted on every brief submission before the work pipeline dispatches
ENFORCED ParetoAnalyzer #1982 -- constructed in api/app.py::_wire_cost_dial_services; consumed by ForecastBudgetController.get_pareto
ENFORCED StubBenchmarkScoreProvider #1982 -- constructed in api/app.py::_wire_cost_dial_services; powers ParetoAnalyzer's quality axis; swap to real benchmark provider when #1980 lands
ENFORCED build_docs_service #1976 -- called in api/app.py::_wire_docs_engine; assembles chunker + indexer + writer + service + facade
ENFORCED DocsService #1976 -- constructed by docs_engine/factory.py::build_docs_service; attached to AppState by _wire_docs_engine
ENFORCED DocChunker #1976 -- constructed inside docs_engine/factory.py::build_docs_service; produces block-aware chunks for the indexer
ENFORCED DocIndexer #1976 -- constructed inside docs_engine/factory.py::build_docs_service; stores PROJECT_DOC memory entries via MemoryBackend.store
ENFORCED DocWriter #1976 -- constructed inside docs_engine/factory.py::build_docs_service; serializes doc + commits on synthorg/docs via the configured GitBackend
ENFORCED ProjectAwareMemoryFacade #1976 -- constructed inside docs_engine/factory.py::build_docs_service; attached to AppState by _wire_docs_engine for transparent project-doc retrieval
ENFORCED DocsToolFactory #1976 -- constructed in api/app.py::_wire_docs_engine; per-task source of WriteLivingDocTool + SearchLivingDocsTool bound to the boot DocsService
ENFORCED WriteLivingDocTool #1976 -- constructed by docs_engine/tool_factory.py::DocsToolFactory.build_tools per task with the agent's project + author binding
ENFORCED SearchLivingDocsTool #1976 -- constructed by docs_engine/tool_factory.py::DocsToolFactory.build_tools per task with the agent's project binding
1 change: 1 addition & 0 deletions scripts/check_no_ghost_wiring.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
# factory + tool-class construction lets the manifest track tool
# wiring (e.g. EPIC #1987 children that add new tool classes).
"src/synthorg/tools/",
"src/synthorg/docs_engine/",
)


Expand Down
Loading
Loading