Skip to content

agent knowledge system#528

Merged
Brad-Edwards merged 9 commits intodevfrom
agent-knowledge-system
Apr 13, 2026
Merged

agent knowledge system#528
Brad-Edwards merged 9 commits intodevfrom
agent-knowledge-system

Conversation

@Brad-Edwards
Copy link
Copy Markdown
Contributor

@Brad-Edwards Brad-Edwards commented Apr 12, 2026

Summary

First slice (issue #522) of the six-slice agent knowledge system rollout.

  • Extends .ground-control.yaml with an optional knowledge section (dir required, schema and inbox optional overrides). Paths are validated against the repo root via a shared resolver that rejects absolute paths and .. traversal.
  • gc_get_repo_ground_control_context now surfaces a resolved knowledge block with existence checks for the directory and schema file. The inbox path is surfaced but not existence-checked; later slices create it on first capture.
  • Commits the docs/knowledge/ skeleton: SCHEMA.md (conventions, source-citation rule, one-repo invariant, flat-navigation rule), index.md (empty content catalog), and log.md (append-only history).
  • Wires this repo's own .ground-control.yaml to point at docs/knowledge/.
  • Fixes stale AGENTS.md wording in mcp/ground-control/README.md so it describes the tool as reading .ground-control.yaml (which it always did).
  • Also lands the unrelated prior commits that already sat on this branch: the design note + implementation order capture, the /implement issue-first entry point with traceability reconciliation, and the bootstrap-claude-workflow hook/skill copy mode.

Requirement UIDs

  • GC-X002 — Knowledge base location declared in repository configuration
  • GC-X003 — One knowledge base per repository, never merged
  • GC-X004 — Knowledge base structure: schema, index, log, content pages
  • GC-X005 — Source citations on every knowledge claim
  • GC-X013 — Knowledge base navigable without retrieval infrastructure

ADR Impact

No ADR required. This slice is purely config wiring plus a documentation skeleton — no new architectural decisions. The agent knowledge system's overall design is captured in docs/notes/agent-knowledge-system-design.md and does not yet warrant an ADR; a future slice that introduces the gc_remember primitive and ingest engine will be the right moment to promote that design note to an ADR if the architecture has stabilized by then.

Ground Control Checks

  • make policy passes
  • gc_evaluate_quality_gates passes or is unchanged by this repo-only change
  • gc_run_sweep reviewed or intentionally deferred with reason

gc_evaluate_quality_gates is unchanged by this slice — no new requirements, no new ADRs, no new code coverage gates introduced. gc_run_sweep is deferred: no new projects, baselines, or sweep watermarks are touched, so a sweep pass is a no-op for this change.

Traceability

  • IMPLEMENTS: mcp/ground-control/lib.js, docs/knowledge/SCHEMA.md, docs/knowledge/index.md, docs/knowledge/log.md, .ground-control.yaml → GC-X002, GC-X003, GC-X004, GC-X005, GC-X013
  • TESTS: mcp/ground-control/lib.test.js → GC-X002, GC-X004, GC-X013 (parser and context-loader behavior; GC-X003 and GC-X005 are documentation invariants not covered by unit tests)
  • DOCUMENTS: mcp/ground-control/README.md, docs/notes/agent-knowledge-system-design.md → GC-X002

Closes #522.

Add the design note for the per-repository agent-maintained knowledge
system under docs/notes/agent-knowledge-system-design.md. This captures
the full design discussion — problem, karpathy three-layer mapping,
hot path (real-time ingest) vs cold path (scheduled sweep), capture /
consume loop, MCP vs CLI layering, config surface, invariants, phasing,
and key decisions — so the requirements can be read alongside the
reasoning that produced them.

Add the implementation order list under docs/notes/agent-knowledge-system-order.md.
One requirement UID per line, in the order they should be implemented
based on the DEPENDS_ON / REFINES edges recorded in Ground Control.

The requirements themselves (GC-X001 through GC-X025) live in Ground
Control. X001 is the umbrella; the 24 children are linked via PARENT
to X001 and connected to each other via DEPENDS_ON and REFINES to
encode the real implementation dependencies so a future planner can
walk the graph without re-deriving order.
Previously /implement took a single Ground Control requirement UID and
derived everything from it — the issue was a side effect created behind
the scenes during Step 1. That model forced every change to be modeled as
a requirement (bug fixes, refactors, dependency bumps and other
requirement-free work had no natural entry point) and could not express
grouped implementation (shipping multiple related requirements in one PR
with coherent review boundaries).

New model: every /implement run is driven by a GitHub issue, and the
issue body declares which requirements are in scope via a conventional
`## Requirements` markdown section containing a bulleted list of UIDs.
Three cases fall out:

  - Empty or missing `## Requirements` section: bug fix / refactor /
    maintenance. Zero requirements are transitioned. Traceability is
    still reconciled against the diff, because a bug fix may touch files
    linked to other requirements whose links are now stale.
  - One UID: equivalent to the old single-requirement flow, just entered
    via an issue.
  - N UIDs: grouped implementation. Step 4.5 clause verification iterates
    the union of clauses across all in-scope requirements. Step 15
    reconciles traceability for all of them. Step 16 transitions each to
    ACTIVE. Step 17 verifies.

Backwards-compatible invocation: `/implement GC-X042` still works. Step 1
detects the input shape, and if it's a UID, finds or creates the matching
issue via existing traceability (or `gc_create_github_issue` if none
exists yet) and treats that issue as the authoritative input. The UID
becomes a single entry in `in_scope_requirements[]`.

Step 15 is also rewritten from "create links for this requirement" to
"reconcile the Ground Control graph against the diff". It walks every
added/modified/renamed/deleted file, finds existing links, and decides
per-file whether to leave the link alone, update the path, create a new
link for behavior that moved, delete a stale link, or flag a coverage
regression for user escalation (when the sole implementation of a
requirement is being deleted). Reconciliation is idempotent: running it
on a branch where the graph already matches is a no-op.

docs/DEVELOPMENT_WORKFLOW.md updated:
  - The workflow heading is now `/implement <issue-number | requirement-uid>`.
  - A new explanation of the two invocation modes, grouped implementation,
    and the `## Requirements` section convention.
  - The mermaid flow diagram updated to show issue-first entry (step 1
    "Resolve issue + parse Requirements section"), Step 17 as
    "Reconcile traceability against diff" rather than "Create traceability
    links", and Step 18 as "Transition in-scope requirements DRAFT → ACTIVE"
    (zero or more).
  - Narrative paragraphs rewritten to call out that reconciliation applies
    regardless of in-scope requirement count, and that a bug fix still
    updates the graph so drift doesn't accumulate.

No code changes — this is entirely a skill + docs change. The existing
MCP surface (`gc_get_traceability_by_artifact`, `gc_create_traceability_link`,
`gc_delete_traceability_link`, `gc_transition_status`, `gc_get_requirement`,
`gh issue view`, `gh issue develop`) is sufficient for the new flow.
Extend .ground-control.yaml with an optional `knowledge` section declaring
the per-repo knowledge base location. `knowledge.dir` is required; `schema`
and `inbox` are optional overrides that default to <dir>/SCHEMA.md and
<dir>/inbox. All knowledge paths are validated against the repository root
via a new shared resolver that rejects absolute paths and `..` traversal.

`gc_get_repo_ground_control_context` now surfaces a resolved `knowledge`
block when the section is configured, with existence checks for the
directory and schema file. The inbox path is surfaced but not existence-
checked; later slices will create it on first capture.

Commit the docs/knowledge/ skeleton (SCHEMA.md, index.md, log.md) and wire
this repo's own .ground-control.yaml to point at it. Fix stale AGENTS.md
wording in mcp/ground-control/README.md that described the tool as reading
from AGENTS.md; the tool reads .ground-control.yaml.

Implements GC-X002, GC-X003, GC-X004, GC-X005, GC-X013.
- lib.js: reject symlink-based escapes in knowledge.dir / schema / inbox
  via realpath containment check in addition to the existing lexical
  check. Canonicalizes the repo root once per request and walks up
  nonexistent ancestors so a symlink on any parent of inbox is still
  caught even when inbox itself is pending creation.
- lib.js / index.js: make requirement_uid optional on
  gc_codex_architecture_preflight and require at least one of
  requirement_uid or issue_number. The prompt builder switches to a
  requirement-free preamble when requirement is null so issue-first
  runs (bugs, refactors, maintenance) can reach architecture preflight
  without manufacturing a fake UID.
- lib.js: formatIssueBody now seeds a ## Requirements section with
  the UID → title bullet so /implement's issue-first parser finds
  in_scope_requirements[] on the round-tripped issue.
- SKILL.md Step 2.5: spell out the UID-optional call signature and
  the issue-number-only fallback.
- SKILL.md Step 15.1: document the origin/dev → dev → origin/main →
  main → git fetch fallback for the reconciliation base ref, matching
  the codex review diff resolver.
- SKILL.md Step 15.6: reconciliation now deletes stale issue→requirement
  links for requirements removed from the issue body, not just adds
  missing ones. Catches the case where an issue was narrowed after
  the initial link set was created.

Tests: +8 cases covering symlink dir escape, symlink schema escape,
symlink-escaping inbox parent, in-repo symlink happy path, preflight
prompt without a requirement, preflight prompt completion line
selection, formatIssueBody Requirements section seeding, and the
title-less formatIssueBody fallback. 88 tests pass, 0 new lint
warnings.
- lib.js: sanitize requirement titles before emitting the
  ## Requirements bullet in formatIssueBody. A multiline title could
  previously inject a second list item that /implement would parse as
  an unrelated UID in in_scope_requirements[]. Collapsing whitespace
  runs to single spaces forces the bullet onto one line.
- lib.js: runCodexArchitecturePreflight fails fast on issue-only runs
  when the GitHub issue body could not be loaded. getIssueContext
  previously swallowed lookup failures and returned {number, warning},
  so a wrong repo slug or missing GH_REPO would let preflight proceed
  against an empty spec.
- lib.js: getIssueContext now accepts a cwd option and
  runCodexArchitecturePreflight passes repoRoot so gh resolves the
  target repository from the checkout's own git config when no
  explicit repo was supplied.
- SKILL.md Step 15.5: rewrite the coverage rule so documentation,
  configuration, and workflow requirements are not forced to produce
  production code and automated tests. IMPLEMENTS is still required
  for every in-scope requirement, but it can point at an ADR, SCHEMA
  page, config file, workflow file, or hook — whichever form of
  implementation the requirement actually demands. TESTS is only
  required when the requirement has testable behavior and the diff
  introduces or touches a verifying test. The no-fabrication and
  no-wrong-link guardrails are made explicit so the agent cannot
  paper over a gap by linking to a plausible-looking neighbor.

Tests: +2 formatIssueBody cases (multiline title injection, tab /
whitespace collapse). 90 tests pass, 0 new lint warnings.
Raise the review cycle cap from 2 to 5 in the /implement and /ship
skills to reflect that the Claude-hosted review steps were removed;
only codex + review-tests remain, so each surviving review gets more
headroom to converge.

lib.js defensive fixes:
- runCodexArchitecturePreflight no longer aborts issue-only runs on
  valid title-only issues. GitHub returns body: "" for these, and
  the old check (!issueContext.body) treated empty string like a
  failed lookup. The check now tests for the warning field or a
  missing body property (not a falsy body value).
- resolveKnowledgeBlock now rejects knowledge.inbox values that point
  at an existing regular file. Before this fix, inbox:
  docs/knowledge/SCHEMA.md slipped through lexical + realpath
  containment and landed as status: ok, silently breaking every
  future capture flow. Nonexistent inboxes remain the happy-path
  state — later slices create the directory on first capture.
- assertRealpathInRepo now walks up past ENOTDIR the same way it
  walks up past ENOENT. Before this fix, inbox: docs/knowledge/
  SCHEMA.md/capture let realpathSync throw ENOTDIR and the exception
  escaped the MCP tool, hard-failing gc_get_repo_ground_control_context
  instead of returning the documented invalid_ground_control_yaml
  envelope. Non-EACCES, non-ENOENT, non-ENOTDIR errors still escape
  — those are real I/O failures, not config drift.

SKILL.md workflow fixes:
- /implement Step 2.5 now preflights every UID in
  in_scope_requirements[], not just the first. Grouped issues that
  carry multiple UIDs (like #522 with its five GC-X00* entries) were
  previously only seeing preflight guardrails for UID #1, and every
  requirement after the first ran without architecture preflight.
- /implement Step 15.5 now has two modes: Mode A is the common case
  where the diff implemented the work (unchanged behavior, every
  requirement needs IMPLEMENTS against a touched file); Mode B is
  the reconciliation-only path where Step 4 concluded the work is
  already done and the graph just needs repair. Mode B accepts
  existing IMPLEMENTS coverage instead of forcing a no-op source
  edit, and backfills missing links against existing files in the
  repo when a requirement has zero existing coverage. Hard-fails
  when no implementing file exists anywhere — that's a requirement
  that should be DEPRECATED, not silently linked.

Tests: +2 cases for knowledge.inbox pointing at a file, and for
inbox descending through a regular file (ENOTDIR path). 92 tests
pass, 0 new lint warnings.
Step 15 was "Reconcile Traceability Links" and Step 16 was "Transition
In-Scope Requirements to ACTIVE". That order does not actually work —
the Ground Control API enforces `IMPLEMENTS → ACTIVE` and returns
`422 requirement_not_active` for every `gc_create_traceability_link`
call with `link_type: IMPLEMENTS` against a DRAFT requirement. A run
following the documented order silently fails 10+ parallel link
creations before it realizes the wall; I hit that and had to reorder
on the fly on this branch.

Swap the two steps so the order matches what the API accepts:
- Step 15 is now "Transition In-Scope Requirements to ACTIVE" — the
  transition is framed semantically as the commit-to-contract moment
  (code exists, reviews are green, the requirement is no longer a
  proposal) rather than a post-traceability bookkeeping chore.
- Step 16 is now "Reconcile Traceability Links Against the Diff" —
  the intro explains that reconciliation must run AFTER transition
  because the API gate would otherwise reject every IMPLEMENTS call.
- Step 17 ("Verify Ground Control State Landed") cross-references
  updated to point at Step 16 for link drift and Step 15 for status
  drift. Added a fourth point explicitly prohibiting silent-failure
  tolerance: if any link-create or transition call returns non-2xx,
  treat it as broken and loop back, do not barrel past it.
- Earlier step 1.10/1.11/4-report cross-references to "Step 15" /
  "Step 16" updated to match the swap.

Step cross-references in the rest of the skill already used Step 14
(final CI re-verification) and Step 18 (report), so those are
unchanged.
@sonarqubecloud
Copy link
Copy Markdown

@Brad-Edwards Brad-Edwards merged commit c4cfd16 into dev Apr 13, 2026
11 checks passed
@Brad-Edwards Brad-Edwards deleted the agent-knowledge-system branch April 13, 2026 01:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant