9.7 KiB
Rendering and visualization
DocForge has three independent ways to present one validated graph generation:
validated generation
├── manual plan → immutable package → detached HTML renderer → declared manual output
├── graph plan → immutable package → detached graph renderer → portable static artifact
└── pinned index → managed loopback viewer → interactive Nodes, Flow, Web, and lazy Logic
They share validated facts but not authority, publication, or lifecycle. A manual render does not publish a portable graph. A portable graph does not start the live viewer. None is canonical project content.
Manual rendering
A generic descriptor may declare a manual template root, isolated preview root, and stable views:
[render]
template_root = ".docforge/templates"
preview_root = ".docforge/previews"
[[render.views]]
id = "manual"
renderer = "generic_html"
template = "manual.html"
output = ".docforge/rendered/manual.html"
title = "My Project Manual"
families = ["architecture", "operations", "system"]
The renderer name is fixed to generic_html. Templates are confined UTF-8 assets with a fixed
token vocabulary. They cannot name commands, Python modules, executable renderers, or arbitrary
publication paths. Raw HTML in canonical Markdown is disabled by the pinned CommonMark path.
Plan and render identity covers the canonical source hash, optional changeset hash, selected nodes and relationships, view configuration, template hash, renderer contract, and parser version.
Use:
docforge --project-root "$PROJECT" render-status
docforge --project-root "$PROJECT" render-status manual --deep
docforge --project-root "$PROJECT" render manual
docforge --project-root "$PROJECT" preview CHANGESET_ID manual
Normal status verifies bounded source, configuration, template, output, renderer, and receipt
identities without reconstructing output. --deep explicitly runs the side-effect-free full-render
oracle. A changeset preview writes only to the isolated preview root.
Manual auto means that a successful canonical application owns regeneration of every declared
manual view. It does not mean background rendering, and ordinary standalone CLI render cannot
select auto; use explicit.
Portable graph rendering
Portable graph configuration is separate:
[graph_render]
output_root = ".docforge/portable-graph"
[[graph_render.views]]
id = "architecture"
renderer = "portable_graph_html"
output = "architecture.html"
title = "Architecture"
root = "architecture.overview"
initial_mode = "web"
depth = 3
max_nodes = 250
max_edges = 1000
max_work = 100000
families = ["architecture", "system"]
relations = ["depends_on", "owns", "calls", "reads", "writes", "tested_by", "relates_to"]
authorities = []
statuses = ["current", "active", "verified"]
tags = []
include_logic = false
A view selects exactly one exact root node or bounded metadata-only lexical query. Exact
filters and node, edge, depth, and work limits close the selection. The initial mode is nodes,
flow, or web. Portable graph contract version 1 excludes function-scoped Logic.
Use:
docforge --project-root "$PROJECT" graph-plan architecture
docforge --project-root "$PROJECT" graph-render architecture
docforge --project-root "$PROJECT" graph-render-status architecture
graph-plan validates and returns the generation-pinned plan without publication. graph-render
is an explicit local CLI publication action. It commits a content-addressed artifact, renderer
receipt, and bounded generation/view manifest in that order; the manifest is the publication
commit. graph-render-status checks only bounded committed evidence and never plans or renders.
MCP may plan and inspect portable graph evidence, but it does not publish the portable artifact. Use the explicit project-local CLI command for publication.
Portable output is a complete static artifact. JavaScript is progressive enhancement, not a requirement for the graph facts to be present.
Live viewer
The live viewer is a managed, read-only browser over one generation-pinned validated SQLite file. Install the per-user manager once:
docforge-viewer-manager install-user-service
Then operate a project viewer:
docforge --project-root "$PROJECT" visualize
docforge --project-root "$PROJECT" visualize --node architecture.overview
docforge --project-root "$PROJECT" visualize --query persistence
docforge --project-root "$PROJECT" visualization-status
docforge --project-root "$PROJECT" visualization-stop
visualize accepts only an optional stable node ID or lexical query, bounded traversal depth, and
the local --no-open presentation choice. It does not accept a project root override, database
path, SQL, template, command, renderer, bind address, or module.
The HTTP listener binds to 127.0.0.1 on an operating-system-selected port. A random token is part
of every accepted path. The server supports only GET and HEAD, sets no-store and restrictive
browser security headers, and has no write, project-selection, arbitrary-query, or static
filesystem endpoint.
The viewer is a snapshot. Index replacement or alteration makes that snapshot fail closed; start a new visualization to use a new validated generation. Source inspection reads only project-confined source evidence bound to the pinned generation.
Nodes, Flow, Web, and Logic
The interactive viewer offers four complementary projections:
- Nodes shows a bounded relation-neutral incoming and outgoing neighborhood.
- Flow presents semantic contributors toward the focus. Prerequisite-style stored relationships may be reversed for presentation without changing stored direction.
- Web expands the convergence picture with contributors, callers, containers, members, and contextual relationships.
- Logic loads a function-scoped control-flow projection only when requested.
Logic supports the explicit control paths published by Python, JavaScript, TypeScript, and C++ integrations. It stays outside the primary graph, portable graph version 1, search, and generation-diff receipts.
Hiding a node is presentation-only. In Flow and Web, ancestors without another path to the focus are removed. In Logic, an omitted-path bridge preserves downstream readability. Restore reverses the presentation change; neither action mutates the index.
Immutable plan and worker boundary
Manual and graph plans are versioned, canonical JSON with deterministic ordering and fixed structural and byte limits. They contain selected graph facts and bounded content, but no live project object, SQLite handle, absolute project or index path, arbitrary query, command, executable path, or caller-selected renderer module.
A projection package binds one plan to inert assets, fixed component versions, a closed built-in renderer identity, and an exact artifact inventory. The detached worker:
- runs one fixed private module through isolated Python;
- uses a trusted working directory and sanitized environment;
- accepts one canonical newline-terminated JSON request;
- returns one bounded canonical JSON response;
- has a fixed renderer allowlist and timeout;
- cannot select graph facts, read project state, choose output paths, or mutate canonical files.
The package contract is bounded, and actual artifact transfer has a fixed 20,000,000-byte ceiling.
A larger descriptor max_render_bytes compatibility value does not widen that worker boundary.
Manual fragment reuse
Manual fragments are disposable semantic cache records, not publication authority. A cold record is accepted only after byte-exact comparison against a full detached render. On a warm hit, the worker independently recomputes the expected fragment before reuse.
Corrupt, forged, stale, incompatible, individually oversized, or aggregate-oversized records fall back to the complete full-render oracle. The current cache is bounded to 10,000 records and 64,000,000 bytes.
Fragment reuse is a correctness and recovery boundary. Do not promise a speedup without current measurements.
Projection policy
The version-2 projection policy is independent of capability mode:
manual: auto | explicit | disabled
portable_graph: explicit | disabled
live_viewer: on-demand | disabled
Set global CLI flags before the subcommand:
docforge --project-root "$PROJECT" --manual-render-policy disabled render manual
docforge --project-root "$PROJECT" --portable-graph-policy disabled graph-plan architecture
docforge --project-root "$PROJECT" --live-viewer-policy disabled visualize
An active operation blocked by policy fails before hidden work. Receipt-only manual and portable status remain available. Viewer status and explicit stop remain available when viewer startup is disabled.
A non-disabled selection also requires its resource: declared manual configuration, declared
portable graph configuration, or viewer runtime. Manual auto additionally requires canonical
application. Read Policy precedence for exact composition.
Failure and recovery
Render input drift detected before replacement fails without publishing a current receipt for stale output. Portable graph publication uses content-addressed evidence and a final manifest commit. Status never repairs implicitly.
Recovery is explicit:
- rerun a manual render from validated canonical state;
- use deep manual status for the full, side-effect-free equivalence oracle;
- rerun portable graph publication, or repair only from validated content-addressed evidence;
- stop and restart a stale live viewer against a current validated index.
Do not recover a derived output by editing its receipt or treating it as canonical. See Recovery and performance, Security, and the Viewer manager.