1
0
Fork 0
Code Issues Pull requests Projects Releases 2 Packages Wiki Activity Actions Pages
DocForge2/docs/PROJECT_DESCRIPTOR.md

9.2 KiB

Project descriptor

A generic DocForge project is selected by one fixed file: .docforge/project.toml beneath an explicit project root. The descriptor is schema version 1. DocForge validates both the JSON-schema shape in schemas/project.schema.json and runtime invariants that schema alone cannot prove.

Reference integrations use a different fixed descriptor, .docforge/reference-adapter.toml; see Reference adapters. Project-owned adapters construct the same runtime ProjectDescriptor contract through the public adapter SDK.

Complete generic example

schema_version = 1
project_id = "my-project"
title = "My Project"
adapter = "generic"

[sources]
content_roots = ["docs/docforge/content"]
authority_files = []

[derived]
cache_root = ".docforge/cache"
index = ".docforge/cache/index.sqlite3"

[changesets]
root = ".docforge/changesets"

[[changesets.writers]]
id = "project-editor"
families = ["architecture", "operations", "system"]
operations = ["create", "update", "move", "delete"]

[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"]

[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

[graph]
allowed_relations = [
  "calls",
  "depends_on",
  "owns",
  "reads",
  "relates_to",
  "tested_by",
  "writes",
]

[limits]
max_source_bytes = 500000
max_nodes = 10000
max_query_chars = 500
max_results = 100
max_traversal_depth = 6
max_context_tokens = 12000
max_tool_output_chars = 200000
max_changesets = 100
max_changeset_operations = 100
max_changeset_bytes = 1000000
max_render_views = 20
max_template_bytes = 1000000
max_render_bytes = 1000000

[[profiles]]
id = "development"
families = ["architecture", "operations", "system"]
statuses = ["current", "active", "verified"]
required_nodes = ["architecture.overview"]
token_budget = 8000
dependency_depth = 3

Rendering sections are optional. Profiles and limits may also be omitted; runtime defaults then apply. The required top-level fields are schema_version, project_id, title, adapter, sources, derived, changesets, and graph.

Identity fields

schema_version must be 1.

project_id is the stable machine identity. It is lowercase and may contain digits, dots, underscores, and hyphens after its first character. Do not derive it from a mutable display title.

title is the human-readable project name.

adapter is generic for this file format. Project-owned adapters publish a validated adapter_id@adapter_version identity through their runtime descriptor; changing adapter identity invalidates incompatible derived state.

The descriptor's byte content contributes to a descriptor hash. Client fragments, launchers, index evidence, and policy results use that hash to detect drift.

Canonical sources

sources.content_roots lists the project-relative directories containing generic Markdown and TOML nodes. Each path must resolve beneath the project root. Canonical content roots may not overlap the derived cache.

sources.authority_files lists additional project-relative regular files whose content belongs to the canonical project identity. They are not automatically parsed as nodes.

A Markdown node contains one TOML metadata block followed by Markdown content:

+++
schema_version = 1
id = "architecture.overview"
title = "Architecture overview"
family = "architecture"
authority = "authoritative"
status = "current"
tags = ["architecture"]
summary = "Defines the top-level architecture and ownership."
+++

# Architecture overview

Describe systems, ownership, runtime flow, failure behavior, and proof.

Every node ID is project-wide and stable. Every relationship target must resolve. A TOML source may contain multiple [[nodes]] records; proposal-enabled multi-node files need stable source_anchor values where creation or movement requires an exact record boundary.

Derived state

derived.cache_root owns disposable indexes, attestations, extraction caches, render receipts, projection artifacts, and viewer registry state.

derived.index must be inside derived.cache_root. Canonical content and cache paths must not overlap.

Derived state is not a backup. If it is deleted or rejected as corrupt, DocForge rebuilds it from validated canonical sources.

Changesets and writers

changesets.root is the confined proposal store. It must not overlap canonical content or the derived cache.

Each changesets.writers entry declares:

  • a stable writer id;
  • the node families that writer may change;
  • allowed operations: create, update, move, and/or delete.

The descriptor grant is necessary but not sufficient. A process must also select that writer at startup, and canonical application requires a separately bound matching applier. Capability mode does not broaden the descriptor grant. See Policy precedence.

Allowed relationships

graph.allowed_relations is the exact project vocabulary accepted on edges. It must be nonempty. Relationship names are stable IDs. DocForge rejects relationships that are not declared and gives depends_on additional cycle validation.

The core does not reinterpret a custom relationship just because its spelling resembles a known term. Task-context retrieval classifies only the documented versioned aliases and preserves unknown allowed relationships as unclassified.

Context profiles

Each profiles entry defines one bounded context compilation:

  • id selects the profile;
  • families and statuses filter eligible nodes;
  • required_nodes names stable nodes that must be present;
  • token_budget limits compiled content;
  • dependency_depth bounds relationship expansion.

Profiles choose derived retrieval scope. They do not change node authority or writer permissions.

Limits

Positive limits bound input, graph, retrieval, proposal, and rendering work. Current defaults are:

  • max_source_bytes = 1000000
  • max_nodes = 10000
  • max_query_chars = 500
  • max_results = 100
  • max_traversal_depth = 8
  • max_context_tokens = 32000
  • max_tool_output_chars = 200000
  • max_changesets = 1000
  • max_changeset_operations = 100
  • max_changeset_bytes = 1000000
  • max_render_views = 100
  • max_template_bytes = 1000000
  • max_render_bytes = 1000000

Smaller project limits are useful policy. They cannot widen fixed internal worker, package, response, or cache ceilings. In particular, detached renderer transfer has its own fixed boundary even if a compatibility descriptor retains a larger max_render_bytes.

Manual rendering

The optional render section declares:

  • one confined template_root;
  • one isolated preview_root;
  • one or more stable views.

Each view uses the built-in generic_html renderer, a template beneath template_root, one declared output path, a title, and a family filter. Paths may not overlap canonical content, authority files, changesets, cache, templates, or previews in unsafe ways.

Templates are inert UTF-8 files with a fixed token vocabulary. They cannot select executable renderers or commands. See Rendering and visualization.

Portable graph rendering

The optional graph_render section declares an output root and one or more portable_graph_html views. Each view selects exactly one:

  • root, an exact stable node ID; or
  • query, a bounded metadata-only lexical seed.

It may then restrict families, relations, authorities, statuses, and tags, plus depth, node, edge, and work limits. initial_mode is nodes, flow, or web. Portable graph contract version 1 requires include_logic = false.

The declared output is relative to graph_render.output_root.

Paths and confinement

Descriptor paths are project-relative. Absolute paths and parent traversal are rejected. Runtime validation also rejects symlink escapes, unexpected file types, unsafe overlap, changing path identity during sensitive reads or publication, and derived outputs outside their declared roots.

The explicit CLI --project-root is the only project selector. The MCP process binds it at startup and exposes no project-switching tool.

Validate changes safely

After editing the descriptor:

docforge --project-root /absolute/path/MyProject validate
docforge --project-root /absolute/path/MyProject reindex
docforge --project-root /absolute/path/MyProject check

Descriptor or adapter implementation drift makes a project-owned running process fail closed; start a fresh process after changing those boundaries.

For first-time creation, prefer the create-only New-project quickstart. For full invariants, read the Core contract.