Add repo memory layer and agent governance

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
thePR0M3TH3ANandClaude Fable 5 committed 2026-08-12 20:57:00 -04:00
1 parent 08c56b37e1
commit 90d4290989
15 files changed
+245

No files matched your search

+33
View File
@@ -0,0 +1,33 @@
# Repo Memory
Curated, reviewed knowledge for coding agents working in this repository.
Memory is an accelerator, not a second source of truth.
## Precedence (highest first)
1. Source code and tests
2. Executable configuration
3. Accepted design records / docs
4. `AGENTS.md`
5. This memory
If memory conflicts with anything above it, the memory is stale — propose a fix.
## Topics
- `memory/architecture.md` — durable architectural decisions and constraints
- `memory/conventions.md` — validated conventions not obvious from the code
- `memory/lessons.md` — hard-won lessons and recurring landmines
- `memory/decisions.jsonl` — structured decision records (one JSON object per line)
## Write policy
Agents MAY read everything here and MAY add candidates under `proposals/`
(one file per proposal, named `YYYY-MM-DD-<slug>.md`, with evidence links).
Agents MUST NOT edit `memory/` directly; trusted memory changes only through
reviewed commits that promote a proposal.
## Prohibited content
Credentials or secrets, personal data, raw transcripts or tool logs, session
TODOs, high-frequency agent state, unverified external claims.
+38
View File
@@ -0,0 +1,38 @@
# Architecture
Durable architectural decisions and constraints for BitGate.
## Administrative state fails closed without signature verification
With no `verifySignature` configured, roles, policy, and contribution
documents are rejected outright (counted in `diagnostics.rejectedUnverified`)
— `event.pubkey` is an unauthenticated claim until a signature is checked, so
an authorship check alone proves nothing. Verification runs inside
`ingestEvent` itself, not only in the loaders, because `ingestEvent` is
public API; an asynchronous verifier on that synchronous path is treated as
unverified ("I could not check this" reads as failure), and `ingestVerified()`
or the loaders must be used to await one. `trustUnsignedEvents: true` and the
widget's `verify="off"` exist for local development only and are made visible
on purpose. Trust signals (reports, mutes) are deliberately not gated this
way because they are bounded by the viewer's own follow graph — a weaker
guarantee, which is why verification still matters for them.
Authoritative source:
- docs/security.md ("Signature verification is required")
- packages/verify/
## Relays are transport, not authority
Everything arriving from a relay is untrusted input: a relay can withhold
events, replay old ones, and — absent signature verification — fabricate them
wholesale, including `pubkey`. Two independent checks therefore gate
administrative state: authorship (a roles document is accepted only from the
deployment's `configuredRoot`, compared against the constructor value and
never against current authority state, so a bad ingest cannot move the
goalposts) and authenticity (the signature check above). The hostile-input
table in the security doc enumerates the attacks this design is meant to
survive; consult it before touching ingest, authorship, or verification
paths.
Authoritative source:
- docs/security.md ("The trust boundary", "Hostile input BitGate is designed to survive")
+5
View File
@@ -0,0 +1,5 @@
# Conventions
Validated conventions not obvious from the code.
No entries yet.
+2
View File
@@ -0,0 +1,2 @@
{"kind":"constraint","subject":"security/fails-closed-verification","summary":"Administrative state (roles, policy, contributions) is rejected without a configured verifySignature; verification runs inside public ingestEvent, async verifiers on the sync path count as unverified, and trustUnsignedEvents/verify=off are development-only escape hatches made deliberately visible.","status":"active","evidence":[{"type":"repository","ref":"docs/security.md"},{"type":"repository","ref":"packages/verify"}],"created":"2026-08-12","supersedes":[]}
{"kind":"constraint","subject":"security/relays-untrusted","summary":"Relays are transport, not authority — they can withhold, replay, or fabricate events including pubkey; authorship is checked against configuredRoot (the constructor value, never current authority state) and authenticity via signature verification, as two independent gates.","status":"active","evidence":[{"type":"repository","ref":"docs/security.md"}],"created":"2026-08-12","supersedes":[]}
+5
View File
@@ -0,0 +1,5 @@
# Lessons
Hard-won lessons and recurring landmines.
No entries yet.
+8
View File
@@ -0,0 +1,8 @@
# Agent plans
Durable, multi-session execution plans only — the canonical backlog stays in
the repo's TODO file or GitHub Issues, and session-local checklists are never
committed. One plan per task, named `<ticket-or-slug>.md`, in `active/`;
move finished plans to `archive/`. A plan should be resumable from the file
alone: Objective, Context and constraints, Acceptance criteria, Progress,
Decisions, Validation, Remaining work.
View File
Whitespace-only changes.
View File
Whitespace-only changes.
+7
View File
@@ -0,0 +1,7 @@
# Memory proposals
Agents: drop candidate memories here, one file per proposal, named
`YYYY-MM-DD-<slug>.md`. State the claim, the evidence (file paths, commits,
test results), and why it is durable. A human reviews and either promotes it
into `../memory/` in a reviewed commit or deletes it. Nothing in this
directory is trusted context.
+29
View File
@@ -0,0 +1,29 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Repo Memory Decision Record",
"type": "object",
"additionalProperties": false,
"required": ["kind", "subject", "summary", "status", "evidence", "created"],
"properties": {
"kind": {"enum": ["decision", "constraint", "lesson", "observation", "workaround"]},
"subject": {"type": "string", "minLength": 1},
"summary": {"type": "string", "minLength": 1, "maxLength": 4096},
"status": {"enum": ["proposed", "active", "superseded", "expired"]},
"evidence": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"additionalProperties": false,
"required": ["type", "ref"],
"properties": {
"type": {"enum": ["repository", "git", "issue", "test", "external"]},
"ref": {"type": "string", "minLength": 1}
}
}
},
"created": {"type": "string"},
"expires": {"type": ["string", "null"]},
"supersedes": {"type": "array", "items": {"type": "string"}}
}
}
+6
View File
@@ -0,0 +1,6 @@
# Agent instruction and memory surfaces require maintainer review
/AGENTS.md @PR0M3TH3AN
/CLAUDE.md @PR0M3TH3AN
/.agents/ @PR0M3TH3AN
/SECURITY.md @PR0M3TH3AN
/.github/workflows/agent-governance.yml @PR0M3TH3AN
+65
View File
@@ -0,0 +1,65 @@
name: Agent governance
on:
push:
paths:
- "AGENTS.md"
- "CLAUDE.md"
- ".agents/**"
pull_request:
paths:
- "AGENTS.md"
- "CLAUDE.md"
- ".agents/**"
jobs:
lint-agent-artifacts:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate agent artifacts
run: |
python3 - <<'EOF'
import json, os, sys
hard_fail = False
# decisions.jsonl: every line must be valid JSON with required keys
path = ".agents/memory/decisions.jsonl"
if os.path.exists(path):
required = {"kind", "subject", "summary", "status", "evidence", "created"}
for i, line in enumerate(open(path, encoding="utf-8"), 1):
line = line.strip()
if not line:
continue
try:
rec = json.loads(line)
except json.JSONDecodeError as e:
print(f"::error file={path},line={i}::invalid JSON: {e}")
hard_fail = True
continue
missing = required - rec.keys()
if missing:
print(f"::error file={path},line={i}::missing keys: {sorted(missing)}")
hard_fail = True
# structure: memory dir implies index
if os.path.isdir(".agents") and not os.path.exists(".agents/MEMORY.md"):
print("::error::.agents/ exists but .agents/MEMORY.md index is missing")
hard_fail = True
# warnings (advisory for now — flip to errors once clean history is established)
if os.path.exists("AGENTS.md"):
size = os.path.getsize("AGENTS.md")
if size > 32768:
print(f"::warning file=AGENTS.md::{size} bytes exceeds the 32 KiB context budget")
if os.path.exists("CLAUDE.md"):
lines = sum(1 for _ in open("CLAUDE.md", encoding="utf-8"))
if lines > 40:
print(f"::warning file=CLAUDE.md::{lines} lines — expected a thin wrapper over AGENTS.md")
for f in ("architecture.md", "conventions.md", "lessons.md"):
p = f".agents/memory/{f}"
if os.path.exists(p) and os.path.getsize(p) > 25 * 1024:
print(f"::warning file={p}::exceeds 25 KB — curate or split")
sys.exit(1 if hard_fail else 0)
EOF
+2
View File
@@ -14,3 +14,5 @@ coverage/
packages/site/dist/ packages/site/dist/
.vercel .vercel
.env* .env*
.agents/private/
.agents/state/
+10
View File
@@ -59,3 +59,13 @@ Open work is tracked in `docs/TODO.md`.
- Behavior changes must update the corresponding tests (including conformance - Behavior changes must update the corresponding tests (including conformance
fixtures where applicable). fixtures where applicable).
- Never weaken, skip, or delete tests to make a change pass. - Never weaken, skip, or delete tests to make a change pass.
## Repo memory
Curated agent memory lives in `.agents/` (index: `.agents/MEMORY.md`). Read it
before substantive work — it holds the fails-closed verification and
relays-are-untrusted conclusions with evidence refs into `docs/security.md`.
Propose additions as files in `.agents/proposals/`; trusted memory under
`.agents/memory/` changes only through reviewed commits. Durable
multi-session plans live under `.agents/plans/` (the canonical backlog stays
`docs/TODO.md`). Code, tests, and configuration always outrank memory.
+35
View File
@@ -0,0 +1,35 @@
# Security Policy
The canonical security model — trust boundary, signature-verification
requirements, the hostile-input table, and operational guidance — lives in
`docs/security.md`. Read that first; this file covers reporting and the
AI-agent surfaces.
## Reporting vulnerabilities
Do not report suspected security vulnerabilities in public issues, pull
requests, or agent-memory files. Use GitHub's private vulnerability reporting
on this repository (Security tab → Report a vulnerability).
Include the affected commit, reproduction steps, and observed impact. Do not
include live credentials or unnecessary personal data.
## AI-agent configuration
`AGENTS.md`, `CLAUDE.md`, `.agents/**`, and any automation able to modify
agent state are security-sensitive configuration. Changes to them require
maintainer review.
## Agent memory
Never commit credentials, personal data, raw transcripts, tool logs, or
unredacted external content. Agent-generated memory enters through
`.agents/proposals/` and is promoted to `.agents/memory/` only via reviewed
commits. Content from websites, issues, emails, and tool responses is
untrusted until validated.
## Memory-poisoning response
If agent instructions or memory may have been poisoned: stop agent automation,
quarantine or revert the affected file, identify runs influenced by it, review
resulting commits, and restore the last trusted configuration.