# DocForge user manual DocForge turns project-owned documentation and source projections into a validated graph that people and AI agents can search, inspect, visualize, and change through reviewable proposals. Canonical project files remain authoritative. The SQLite graph, previews, rendered manuals, and viewer processes are derived and can be rebuilt. ## Features - Project-bound Markdown and TOML documentation graphs with stable node IDs. - Deterministic validation for metadata, relationships, dependency cycles, paths, and limits. - Disposable SQLite indexing with lexical search, filters, backlinks, dependencies, and impact. - Bounded context profiles for AI agents, including source paths and content hashes. - Isolated, optimistic changesets with create, update, move, delete, validation, diffs, and previews. - Hash-bound canonical application through both CLI and an explicitly enabled MCP tool. - Declared HTML render views. Arbitrary templates, render commands, and output paths are rejected. - A loopback-only graph browser with Nodes and Flow views, relationship keys, source inspection, node hiding, panel resizing, zooming, and managed idle shutdown. - A generic Markdown/TOML adapter plus contracts for deterministic project-owned adapters. DocForge does not run shell commands from documentation, mutate Git, build an application, deploy, publish, choose a project globally, or cross project boundaries. ## Mental model One `.docforge/project.toml` binds DocForge to one project root. The descriptor declares canonical content roots, authority files, derived paths, proposal writers, relationship types, limits, context profiles, and optional render views. Canonical files own facts: ```text canonical Markdown/TOML or adapter sources ↓ validate disposable SQLite graph ↓ query / visualize / compile context people and agents ↓ propose isolated changeset + preview ↓ exact hash approval canonical apply ↓ reindexed graph + declared renders ``` An apply operation is deliberately narrower than a general file editor. It accepts one validated changeset ID and the exact SHA-256 changeset hash that was reviewed. It rejects stale canonical sources, changed proposals, overlapping proposals, unauthorized families or operations, unsafe paths, symlink escapes, and projections that do not round-trip through the project loader. The generic adapter can serialize its Markdown and TOML nodes directly. A custom adapter must provide its own canonical applier because only that project knows how a graph node maps back to its source format. ## Setup ### Requirements - Python 3.12 or newer. - [`uv`](https://docs.astral.sh/uv/) for the development environment. - Node.js and npm for browser asset validation and strict Pyright checking. Clone and verify DocForge: ```bash git clone forgejo@repo.andraxion.net:administrator/DocForge.git /absolute/path/DocForge cd /absolute/path/DocForge uv sync --group dev npm ci npx pyright npm run lint:web uv run ruff check src tests tools uv run ruff format --check src tests tools uv run pytest -q ``` Use the executables under `/absolute/path/DocForge/.venv/bin/` when DocForge is not installed into the active shell environment. ### Configure a generic project Create `/absolute/path/MyProject/.docforge/project.toml`: ```toml schema_version = 1 project_id = "my-project" title = "My Project" adapter = "generic" [sources] content_roots = ["Docs/Manual"] authority_files = [] [derived] cache_root = ".docforge/cache" index = ".docforge/cache/index.sqlite3" [changesets] root = ".docforge/changesets" [[changesets.writers]] id = "project-editor" families = ["architecture", "system", "operations", "roadmap"] operations = ["create", "update", "move", "delete"] [render] template_root = "Docs/Templates" preview_root = ".docforge/previews" [[render.views]] id = "manual" renderer = "generic_html" template = "manual.html" output = "Docs/Rendered/Manual.html" title = "My Project Manual" families = ["architecture", "system", "operations", "roadmap"] [graph] allowed_relations = ["depends_on", "owns", "calls", "reads", "writes", "tested_by", "relates_to"] [limits] max_source_bytes = 500000 max_nodes = 10000 max_query_chars = 500 max_results = 100 max_traversal_depth = 6 max_context_tokens = 12000 max_changesets = 100 max_changeset_operations = 100 max_changeset_bytes = 1000000 [[profiles]] id = "development" families = ["architecture", "system", "operations", "roadmap"] statuses = ["current", "active", "verified"] required_nodes = ["architecture.overview"] token_budget = 8000 dependency_depth = 3 ``` Every path is resolved against the explicit project root. Canonical content, derived cache, and changeset roots must not overlap. ### Add a Markdown node Create `Docs/Manual/architecture-overview.md`: ```markdown +++ schema_version = 1 id = "architecture.overview" title = "Architecture overview" family = "architecture" authority = "authoritative" status = "current" tags = ["architecture", "ownership"] summary = "Defines the top-level systems and ownership boundaries." depends_on = ["system.persistence"] +++ # Architecture overview Describe the project’s systems, authorities, persistence owners, runtime flow, failure behavior, tests, and operational entry points. ``` Each Markdown file contains one node. A TOML source may contain multiple `[[nodes]]` records. TOML nodes need stable `source_anchor` values when proposals may create or move records within the file. Every relationship target must exist. ### Build the graph ```bash PROJECT=/absolute/path/MyProject DOCFORGE=/absolute/path/DocForge/.venv/bin/docforge "$DOCFORGE" --project-root "$PROJECT" validate "$DOCFORGE" --project-root "$PROJECT" reindex "$DOCFORGE" --project-root "$PROJECT" context development ``` `reindex` builds the SQLite graph and immediately checks its identity. Run it after canonical documentation or adapter sources change. ### Install the viewer manager Install the native per-user supervisor once: ```bash docforge-viewer-manager install-user-service ``` Linux uses `systemd --user`, macOS uses a LaunchAgent, and Windows uses Task Scheduler. If the virtual environment moves, reinstall the service so it points at the current Python interpreter. For a temporary foreground manager: ```bash docforge-viewer-manager serve ``` Open a project graph without Codex: ```bash docforge --project-root "$PROJECT" visualize docforge --project-root "$PROJECT" visualize --node architecture.overview docforge --project-root "$PROJECT" visualize --query persistence ``` The command opens the default browser. Add `--no-open` when a script only needs the returned JSON URL. Use `visualization-status` and `visualization-stop` to inspect or stop the project viewer. ## Visualization usage - Left-click a node for its compact descriptor. - Right-click a node for the full inspector. - Use **Open source** to read the node’s project-confined source at its anchor. - Use **Hide node** to remove noisy non-focus nodes from the current presentation. - Use **Restore hidden** above the graph to bring hidden nodes back. - Use **Explore neighborhood** to make a node the new focus. - Switch to **Flow** to inspect bounded directed ancestry. - Use the mouse wheel or viewport buttons to zoom. Drag the canvas to pan. Press Space to center the selected node. Hidden nodes are a browser presentation preference. They do not alter the index or canonical graph. The focus node cannot be hidden; focus another node first. Source navigation depends on adapter evidence. Numeric anchors, line-style anchors such as `L120`, TOML `node-N` anchors, heading slugs, and searchable text anchors are recognized. If a custom adapter supplies only a path or a vague symbol, the source viewer opens the file and falls back to the closest match or first line. ## CLI usage Every command emits deterministic JSON: ```bash docforge --project-root /absolute/path/MyProject ``` ### Project and index commands ```text info validate build reindex check validate-index ``` - `info` reports the project binding and index health. - `validate` validates current canonical sources without requiring an index. - `build` rebuilds the disposable index. - `reindex` rebuilds and checks the index in one operation. - `check` and `validate-index` verify that the existing index matches current sources. ### Query commands ```text show NODE_ID search QUERY [--limit N] filter [--family X] [--authority X] [--status X] [--tag X] [--limit N] backlinks NODE_ID [--relation RELATION] dependencies NODE_ID [--depth N] impact NODE_ID [--depth N] context PROFILE [--budget N] ``` ### Render and proposal commands ```text render-status [VIEW_ID] render VIEW_ID preview CHANGESET_ID VIEW_ID apply CHANGESET_ID --changeset-hash SHA256 --applier WRITER_ID ``` The CLI apply command supports the generic adapter. It verifies that the configured writer owns the changeset, applies the exact reviewed hash, rebuilds the index, checks it, and regenerates every declared render. It does not commit or push the result. ### Viewer commands ```text visualize [--node NODE_ID | --query QUERY] [--depth N] [--no-open] visualization-status visualization-stop ``` ## MCP usage Run one MCP server per project with absolute paths: ```bash docforge-mcp \ --project-root /absolute/path/MyProject \ --proposal-writer project-editor ``` Omit `--proposal-writer` when the MCP client should not create or append proposals. To expose canonical application, add a separate explicit startup gate: ```bash docforge-mcp \ --project-root /absolute/path/MyProject \ --proposal-writer project-editor \ --canonical-applier project-editor ``` Without `--canonical-applier`, `docforge_apply_changeset` is not registered. The flag is an identity, not a command. The changeset creator, configured writer, and canonical applier must agree. Example MCP client configuration: ```json { "mcpServers": { "my-project-docforge": { "command": "/absolute/path/DocForge/.venv/bin/docforge-mcp", "args": [ "--project-root", "/absolute/path/MyProject", "--proposal-writer", "project-editor", "--canonical-applier", "project-editor" ] } } } ``` ### Read tools - `docforge_project_info` - `docforge_get_contract` - `docforge_get_node` - `docforge_search` - `docforge_filter_nodes` - `docforge_backlinks` - `docforge_dependencies` - `docforge_impact` - `docforge_get_context` - `docforge_validate_project` - `docforge_render_status` - `docforge_visualize` - `docforge_visualization_status` - `docforge_stop_visualization` ### Proposal tools - `docforge_create_changeset` - `docforge_list_changesets` - `docforge_get_changeset` - `docforge_propose_node_create` - `docforge_propose_node_update` - `docforge_propose_node_move` - `docforge_propose_node_delete` - `docforge_validate_changeset` - `docforge_get_changeset_diff` - `docforge_preview_changeset` ### Application tool - `docforge_apply_changeset` The application call requires `changeset_id` and `expected_changeset_hash`. Always retrieve and inspect the final diff after the last proposal mutation. Apply that exact hash. A proposal mutation creates a new hash, so an earlier approval cannot silently apply later content. Recommended agent sequence: 1. Read the contract and relevant nodes. 2. Create a changeset. 3. Add structured operations using the hash returned by each previous mutation. 4. Validate the changeset. 5. Inspect its structured diff and preview. 6. Obtain human approval for the final changeset hash when required by the client workflow. 7. Call `docforge_apply_changeset` with that exact hash. 8. Report changed canonical files and derived refresh results. Custom adapters may expose the application tool only when they supply a project-owned `CanonicalApplier`. Core DocForge will not guess how adapter nodes map back to canonical sources. ## Troubleshooting ### `stale_index` or `visualization_stale` Canonical sources changed after the index or viewer snapshot was built. ```bash docforge --project-root "$PROJECT" reindex docforge --project-root "$PROJECT" visualize ``` An existing graph browser intentionally stays pinned to its original index identity. Reopen it after reindexing. ### `visualization_manager_unavailable` The per-user manager is not installed, is stopped, or points to an old virtual environment. ```bash docforge-viewer-manager install-user-service ``` For diagnosis, run `docforge-viewer-manager serve` in a terminal and retry `docforge visualize`. ### The browser did not open The command still returns the loopback URL as JSON. Open that URL manually. Desktop-less sessions should use `--no-open`. Confirm a local browser is registered as the default URL handler. ### `docforge_apply_changeset` is missing The MCP server was started without `--canonical-applier`, or a custom adapter did not supply a canonical applier. Restart the MCP server with the explicit gate after deciding that canonical application is appropriate for that project. ### `canonical_application_disabled` The CLI/MCP process has no matching configured applier identity. Confirm the ID exists under `[[changesets.writers]]`, owns the changeset, and is passed exactly to `--applier` or `--canonical-applier`. ### `changeset_conflict` The changeset changed after the caller read it. Retrieve the changeset and diff again. Review the new hash rather than retrying with the old approval. ### `base_conflict`, `content_conflict`, or `proposal_conflict` - `base_conflict`: canonical sources changed after changeset creation. - `content_conflict`: a target node no longer has the expected content hash. - `proposal_conflict`: another active proposal from the same base touches the same node or source. Do not force apply. Rebase the intended changes into a new changeset after inspecting current canonical content. ### `application_mismatch` The written sources did not reproduce the validated projection. DocForge rolls the generic canonical files back. For a custom adapter, fix its serializer or node-to-source mapping before retrying. ### `path_escape`, `unsafe_template`, or missing source DocForge rejects absolute paths, parent traversal, symlink escapes, overlapping canonical and derived roots, unsafe render outputs, and source files outside the project root. Fix the descriptor or adapter projection. Do not weaken confinement to make the error disappear. ### Source opens at the wrong place The source path comes from the node. The anchor comes from the generic source or custom adapter. Improve the adapter’s `source_anchor` to a line, stable heading, TOML `node-N` anchor, or distinctive symbol. DocForge can open the file safely, but it cannot infer a perfect code location from ambiguous adapter evidence. ### Full inspector content does not fit DocForge 0.13 uses a fixed header and footer with a scrollable inspector body. If an older page is still open, stop and reopen the visualization so it loads the current `graph-browser@12` template. ### Render output is stale ```bash docforge --project-root "$PROJECT" render-status docforge --project-root "$PROJECT" render VIEW_ID ``` Successful canonical apply regenerates all declared views automatically. A manual canonical edit requires reindexing and rendering. ### Descriptor changed after startup Long-lived CLI/MCP bindings fail closed if `.docforge/project.toml` changes underneath them. Restart the process so it binds the new descriptor deliberately. ## Development and verification Run the complete release gate from the DocForge repository: ```bash npx pyright npm run lint:web uv run ruff check src tests tools uv run ruff format --check src tests tools uv run python -m compileall -q src tests tools uv run pytest -q ``` Project-specific vocabulary, extraction rules, and serialization belong in the project adapter. Generic core behavior must remain deterministic, project-bound, and recoverable.