698 lines
27 KiB
Markdown
698 lines
27 KiB
Markdown
# 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.
|
||
|
||
DocForge 1.0.0 is the first stable product release. It includes the project-scoped graph,
|
||
CLI and MCP query surfaces, hash-approved proposal application, generic and project-owned adapters,
|
||
declared rendering, and the Nodes/Flow/Web visualization model documented below.
|
||
|
||
Later incremental-compiler capabilities are additive. A Release 1 adapter with only
|
||
`load_projection()` remains valid and follows the same complete-rebuild path. No existing project
|
||
descriptor, canonical document, changeset, or adapter must be rewritten. Source-scoped caching and
|
||
lazy logic projections activate only for adapters that explicitly implement the optional
|
||
incremental methods while retaining the full loader as a fallback.
|
||
|
||
## 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.
|
||
- Relationship-only changeset operations that do not rewrite node content.
|
||
- Hash-bound canonical application through both CLI and an explicitly enabled MCP tool.
|
||
- Opt-in incremental adapter extraction with reverse-dependency invalidation.
|
||
- Lazy function-scoped logic projections that do not densify the primary graph.
|
||
- Declared HTML render views. Arbitrary templates, render commands, and output paths are rejected.
|
||
- A loopback-only graph browser with Nodes, semantic Flow, and convergence Web views,
|
||
relationship keys, source inspection, branch-aware 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 **Explore neighborhood** to make a node the new focus.
|
||
- Use the mouse wheel or viewport buttons to zoom. Drag the canvas to pan. Press Space to center
|
||
the selected node.
|
||
|
||
### Nodes: bounded neighborhood
|
||
|
||
**Nodes** answers: “What is immediately related to this thing?”
|
||
|
||
DocForge starts at the focus and traverses every stored incoming and outgoing relationship up to
|
||
the selected depth and fixed edge limit. The graph preserves the relationships exactly as the
|
||
index stores them. It does not reinterpret direction or exclude contextual relationships.
|
||
|
||
The focus appears at the center. Every other card is categorized by the relationship that explains
|
||
its contribution to the focus: Structure, Behavior, Dependency, Execution, Data, Evidence,
|
||
Context, or Related. This is the broadest view and is useful for inspecting raw adapter output,
|
||
discovering nearby nodes, and choosing a better focus. It can also be the noisiest view because
|
||
containment, documentation, dependencies, calls, imports, and other relationship types may all
|
||
appear together.
|
||
|
||
In Nodes, **Hide node** removes that node and its incident edges from the presentation. It does not
|
||
remove other nodes merely because they become disconnected.
|
||
|
||
### Flow: semantic paths into the focus
|
||
|
||
**Flow** answers: “What origins and prerequisites lead to this thing?”
|
||
|
||
Flow builds bounded semantic paths whose destination is the focus. Structural and execution
|
||
relationships already aimed at the consumer keep their stored direction. Prerequisite-style
|
||
relationships are reversed for presentation so arrows consistently point toward the thing being
|
||
explained:
|
||
|
||
- `defined_in`, `inherits`, and `imports` become definition, base-class, and imported-module
|
||
contributions.
|
||
- `depends_on` and `reads` become dependency and data-source contributions.
|
||
- `tested_by` becomes a test path into the exercised node.
|
||
|
||
For example, a method can appear as:
|
||
|
||
```text
|
||
tests package → test module → test class → test method
|
||
```
|
||
|
||
The displayed reversal is a visualization rule only. It does not mutate the canonical
|
||
relationship or derived index. Context-only relationships such as `documents`, `governs`, and
|
||
`relates_to` are omitted so Flow remains a focused origin-to-destination explanation.
|
||
|
||
### Web: convergence and makeup
|
||
|
||
**Web** answers: “What makes up this thing, and what paths converge on it?”
|
||
|
||
Web starts with the same semantic contributor direction as Flow, then includes contextual
|
||
relationships that Flow intentionally omits. It can show callers, containers, imports,
|
||
dependencies, evidence, documentation context, and other contributors converging on the focus.
|
||
It also presents direct relationships owned by the focus as adjacent contributor branches,
|
||
including supported `calls`, `contains`, `defines`, `dispatches_to`, `implemented_by`, `launches`,
|
||
`writes`, and `activates` relationships.
|
||
|
||
This makes classes and methods useful graph nodes rather than labels attached to a file. A class
|
||
can show its containing module, base class, callers, tests, and methods. A method can show the
|
||
package and class path that contains it alongside imported helpers, dependencies, callers, and
|
||
evidence. Every displayed path is oriented toward the focused node.
|
||
|
||
Adjacent traversal is deliberately bounded. After DocForge includes a direct member or execution
|
||
dependency owned by the focus, it continues toward that branch rather than fanning back out
|
||
through unrelated siblings. Depth and edge limits provide a second guard against an unbounded web.
|
||
|
||
### Logic: possible control paths
|
||
|
||
**Logic** answers: “What decisions and actions can occur inside this function or method?”
|
||
|
||
Logic appears when the focused node owns a function-scoped `LogicProjection`. It loads that
|
||
projection on demand instead of adding statements and conditions to the primary architecture
|
||
graph. The view presents:
|
||
|
||
- **Entry** and **Exit** terminals.
|
||
- **Decision** cards for `if`, `elif`, compound booleans, loop conditions, `match` cases, and
|
||
assertions.
|
||
- **Action** cards for executable statement blocks and calls.
|
||
- **Control** cards for loops, `break`, and `continue`.
|
||
- **Convergence** cards where alternate paths rejoin, including decision, case, loop-exit, and
|
||
exception convergence.
|
||
- **Terminal** cards for returns and raised exceptions.
|
||
|
||
Edges use explicit labels and independent colors for `TRUE`, `FALSE`, `NEXT`, `CASE`, `LOOP`,
|
||
`EXCEPTION`, `RETURN`, `RAISE`, `BREAK`, and `CONTINUE`. Long predicates wrap on the card. The full
|
||
expression and source anchor remain available through inspection and source navigation.
|
||
|
||
The built-in analyzers cover Python, JavaScript, and C++. Python uses the standard-library AST.
|
||
JavaScript and C++ use pinned Tree-sitter grammars behind the same language-neutral
|
||
`LogicProjection` contract. Tree-sitter handles concrete syntax; DocForge keeps a thin
|
||
language-specific control-flow profile for constructs such as conditions, loops, cases,
|
||
exceptions, returns, and short-circuit operators. Adding a language therefore requires a grammar
|
||
and a semantic profile, not a new visualization or database design.
|
||
|
||
Logic is static analysis. It shows paths the indexed source permits, not the branch that ran for a
|
||
particular request or the runtime value of a boolean. Dynamic dispatch, reflection, generated
|
||
behavior, and values returned by other processes may require runtime tracing to resolve.
|
||
|
||
### Finding the right node
|
||
|
||
The left panel combines independent filters rather than forcing users to scan the complete node
|
||
list:
|
||
|
||
- **Text** searches indexed titles, summaries, and content.
|
||
- **Family** selects the project-defined family.
|
||
- **Node type** selects callables or an exact indexed kind such as function, method, class, route,
|
||
test, module, or document.
|
||
- **Language** selects an indexed language tag such as Python, JavaScript, or C++.
|
||
- **Capability** selects nodes with source navigation or an available Logic projection.
|
||
|
||
Quick presets select common combinations for Logic-ready nodes, Python callables, tests, routes,
|
||
and documentation. Filters compose, so `JavaScript` plus `Logic available` lists only JavaScript
|
||
functions that can open Logic. Result cards show the readable leaf name, kind, language, path, and
|
||
source anchor. Full identities remain in the tooltip and inspector.
|
||
|
||
Selecting any canvas node highlights its directly connected nodes and the exact edges between
|
||
them. Other nodes and edges remain visible at reduced opacity. This local trace works in Nodes,
|
||
Flow, Web, and Logic without changing the root or querying a different graph.
|
||
|
||
### Reading graph cards
|
||
|
||
The canvas presents nodes as compact semantic cards rather than anonymous circles:
|
||
|
||
- **Focus** identifies the node being explained.
|
||
- **Structure** identifies packages, modules, classes, methods, definitions, and other containment
|
||
paths that establish where the focus exists.
|
||
- **Behavior** identifies base classes, derived classes, and implementation relationships.
|
||
- **Dependency** identifies imported modules and required services or helpers.
|
||
- **Execution** identifies callers, dispatchers, launchers, activators, and focus-owned execution
|
||
branches.
|
||
- **Data** identifies values or resources read and written.
|
||
- **Evidence** identifies tests, verification, governing rules, and documentation.
|
||
- **Context** identifies descriptive relationships that do not imply execution or ownership.
|
||
- **Related** is the deterministic fallback for adapter-specific relationships that do not fit a
|
||
built-in category.
|
||
|
||
The colored rail, category badge, edge style, and relationship label provide separate visual cues.
|
||
Color is not the only signal. Cards also display the node kind, such as `Test class` or
|
||
`Test method`.
|
||
|
||
Canvas cards use the readable leaf name. For example,
|
||
`tests.test_settings.SettingsTests.test_default_settings_load` appears as
|
||
`test_default_settings_load`, while `tests.test_settings` appears as `test_settings`. Long leaf
|
||
names wrap at identifier boundaries instead of being truncated. The complete qualified title and
|
||
stable node ID remain available in the pointer tooltip, compact descriptor, and full inspector, so
|
||
the shorter canvas label never changes identity or loses information.
|
||
|
||
### Hiding nodes and pruning ancestors
|
||
|
||
Hidden nodes are browser presentation state. Hiding never changes canonical files, the derived
|
||
index, or future graph queries. The focus cannot be hidden; focus another node first.
|
||
|
||
- In **Nodes**, hiding removes only the selected node and its incident edges.
|
||
- In **Flow** and **Web**, hiding removes the selected node, then prunes every upstream ancestor
|
||
whose only remaining route to the focus passed through it.
|
||
- In **Logic**, hiding removes the selected control-flow step and inserts an `omitted` bridge
|
||
between its visible predecessors and successors. This preserves the readable path without
|
||
pretending the hidden code disappeared from the indexed source.
|
||
- Descendant nodes between the hidden node and the focus remain visible.
|
||
- Ancestors with another valid path to the focus remain visible through that alternate path.
|
||
- The status line reports how many nodes were hidden or isolated.
|
||
- **Restore hidden** clears the hidden-node set and rebuilds the complete current view.
|
||
|
||
This behavior lets a user cut away a noisy or irrelevant branch without losing the useful
|
||
downstream chain that explains how the remaining nodes reach the focus.
|
||
|
||
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 <command>
|
||
```
|
||
|
||
### 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_get_logic`
|
||
- `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_relationship_update`
|
||
- `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.
|
||
|
||
Use `docforge_propose_relationship_update` when the intended change is only an edge addition or
|
||
removal. It uses the same underlying validated update contract, but rejects empty relationship
|
||
lists and makes it explicit that node content will remain unchanged.
|
||
|
||
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.
|
||
|
||
## Incremental adapter compilation
|
||
|
||
Release 1 complete-projection adapters remain supported. Adapters with large source trees can
|
||
implement the optional source-scoped manifest and extraction contract. DocForge then fingerprints
|
||
sources, reuses unchanged facts, reparses changed sources and their reverse dependents, validates a
|
||
complete candidate graph, and publishes the index atomically.
|
||
|
||
DocForge detects this capability structurally. An adapter without both `load_manifest()` and
|
||
`extract_source()` remains on the Release 1 path. Its behavior and query results are unchanged, but
|
||
it does not receive incremental performance until it opts in.
|
||
|
||
Build results report cache hits, reparsed sources, invalidated sources, deleted sources, and total
|
||
sources. A full projection remains the fallback and equivalence oracle.
|
||
|
||
Manual proposals remain separate from compilation. Applying an approved changeset updates
|
||
canonical sources first. Incremental compilation then notices those changed source fingerprints;
|
||
it never treats an unapplied proposal as canonical.
|
||
|
||
Function-scoped `LogicProjection` data is cached alongside its owning source but remains separate
|
||
from the primary Nodes, Flow, and Web graph. The Logic tab and `docforge_get_logic` load one
|
||
function or method on demand without adding every condition and basic block to ordinary graph
|
||
traversal.
|
||
|
||
See [Incremental Adapter Indexing](INCREMENTAL_INDEXING.md) for the complete contract, cache
|
||
invalidation rules, manual-application lifecycle, and lazy Logic boundary.
|
||
|
||
## 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 1.0 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@17` 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.
|