diff --git a/.agents/MEMORY.md b/.agents/MEMORY.md new file mode 100644 index 00000000..e64f65f9 --- /dev/null +++ b/.agents/MEMORY.md @@ -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-.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. diff --git a/.agents/memory/architecture.md b/.agents/memory/architecture.md new file mode 100644 index 00000000..0d0c643c --- /dev/null +++ b/.agents/memory/architecture.md @@ -0,0 +1,18 @@ +# Architecture + +Durable architectural decisions and constraints for SeedPass. + +## TypeScript port: Python stays authoritative until parity is proven + +The `port/typescript-web-extension` effort re-implements SeedPass as a +protocol-compatible TypeScript core with thin adapters (CLI, static/PWA web +app, browser extension, optional Tauri desktop) — not a screen-by-screen port +of the Python TUI. The Python implementation remains the reference, and the +TypeScript implementation becomes authoritative only after deterministic +derivation, vault compatibility, sync compatibility, and safety tests pass. +Hard non-goals: no plaintext seeds/passwords/TOTP secrets/private keys in +browser `localStorage`, no hosted-server requirement, no analytics/telemetry, +no large frontend dependency graph for cryptographic behavior. + +Authoritative source: +- docs/typescript_web_extension_port_plan.md (§1–3) diff --git a/.agents/memory/conventions.md b/.agents/memory/conventions.md new file mode 100644 index 00000000..f52d3677 --- /dev/null +++ b/.agents/memory/conventions.md @@ -0,0 +1,25 @@ +# Conventions + +Validated conventions not obvious from the code. + +## Deterministic artifact generation + +All generated artifacts (passwords, keys, TOTP secrets, etc.) must be fully +deterministic across runs and platforms. Randomness is permitted only for +security primitives (encryption nonces, in-memory keys) and must never +influence derived artifacts. + +Authoritative source: +- AGENTS.md (§Deterministic Artifact Generation) +- docs/typescript_web_extension_port_plan.md + +## New entry kinds follow the extension checklist + +Adding a new entry `kind` (ssh, seed, ...) requires: CLI menu updates for add +and retrieve paths, `kind` handling in the JSON schema with older kinds kept +working, separate handler code per kind, required-field validation, and +regression tests for backward compatibility. + +Authoritative source: +- AGENTS.md (§Integrating New Entry Types) +- docs/entry_types.md diff --git a/.agents/memory/decisions.jsonl b/.agents/memory/decisions.jsonl new file mode 100644 index 00000000..f388ba0d --- /dev/null +++ b/.agents/memory/decisions.jsonl @@ -0,0 +1,4 @@ +{"kind":"constraint","subject":"crypto/deterministic-artifacts","summary":"All derived artifacts (passwords, keys, TOTP secrets) must be fully deterministic across runs and platforms; randomness is allowed only for security primitives such as encryption nonces and in-memory keys and must never influence derived artifacts.","status":"active","evidence":[{"type":"repository","ref":"AGENTS.md"},{"type":"repository","ref":"docs/typescript_web_extension_port_plan.md"}],"created":"2026-08-12","supersedes":[]} +{"kind":"constraint","subject":"index/legacy-migration","summary":"Index-format or encryption changes must provide a migration path that detects and upgrades legacy archives (including pre-salt, pre-password-encryption indexes), keeps older account indexes unlockable and Nostr sync working, and is covered by regression tests.","status":"active","evidence":[{"type":"repository","ref":"AGENTS.md"},{"type":"repository","ref":"docs/typescript_web_extension_port_plan.md"}],"created":"2026-08-12","supersedes":[]} +{"kind":"decision","subject":"port/typescript-authority","summary":"The TypeScript port is a protocol-compatible core with thin interface adapters; the Python implementation remains the reference and TypeScript becomes authoritative only after deterministic derivation, vault compatibility, sync compatibility, and safety tests pass.","status":"active","evidence":[{"type":"repository","ref":"docs/typescript_web_extension_port_plan.md"}],"created":"2026-08-12","supersedes":[]} +{"kind":"decision","subject":"entries/kind-extension-rules","summary":"New entry kinds are integrated via the fixed checklist in AGENTS.md: menu updates, schema kind field with backward-compatible handlers, separate handler code per kind, validation, and regression tests.","status":"active","evidence":[{"type":"repository","ref":"AGENTS.md"},{"type":"repository","ref":"docs/entry_types.md"}],"created":"2026-08-12","supersedes":[]} diff --git a/.agents/memory/lessons.md b/.agents/memory/lessons.md new file mode 100644 index 00000000..b0a2bae6 --- /dev/null +++ b/.agents/memory/lessons.md @@ -0,0 +1,16 @@ +# Lessons + +Hard-won lessons and recurring landmines. + +## Legacy index migration is mandatory + +Every index-format or encryption change must ship a migration path: detect +legacy archives (including pre-salt / pre-password-encryption indexes), +upgrade them to the current schema, keep older account indexes unlockable and +Nostr synchronization working, and add regression tests. The TS port extends +this: migration must refuse unknown future schema versions instead of +silently writing. + +Authoritative source: +- AGENTS.md (§Legacy Index Migration) +- docs/typescript_web_extension_port_plan.md diff --git a/.agents/plans/README.md b/.agents/plans/README.md new file mode 100644 index 00000000..36bcc9a5 --- /dev/null +++ b/.agents/plans/README.md @@ -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 `.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. diff --git a/.agents/plans/active/.gitkeep b/.agents/plans/active/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/.agents/plans/archive/.gitkeep b/.agents/plans/archive/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/.agents/proposals/README.md b/.agents/proposals/README.md new file mode 100644 index 00000000..89c95bdd --- /dev/null +++ b/.agents/proposals/README.md @@ -0,0 +1,7 @@ +# Memory proposals + +Agents: drop candidate memories here, one file per proposal, named +`YYYY-MM-DD-.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. diff --git a/.agents/schemas/memory.schema.json b/.agents/schemas/memory.schema.json new file mode 100644 index 00000000..e14a43d9 --- /dev/null +++ b/.agents/schemas/memory.schema.json @@ -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"}} + } +} diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..d41162ce --- /dev/null +++ b/.github/CODEOWNERS @@ -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 diff --git a/.github/workflows/agent-governance.yml b/.github/workflows/agent-governance.yml new file mode 100644 index 00000000..cc88ebe7 --- /dev/null +++ b/.github/workflows/agent-governance.yml @@ -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 diff --git a/.gitignore b/.gitignore index 30b9fe02..04fe61af 100644 --- a/.gitignore +++ b/.gitignore @@ -57,3 +57,7 @@ torch/torch/ memory-update.md memory-update.json .claude/ + +# Agent-local memory state (never committed) +.agents/private/ +.agents/state/ diff --git a/AGENTS.md b/AGENTS.md index cfff452f..b961a4ff 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -250,3 +250,10 @@ new `kind` (for example, SSH keys or BIP‑39 seeds) use the checklist below: This procedure keeps the UI consistent and ensures new data types integrate smoothly with existing functionality. + +## Repo memory + +Curated agent memory lives in `.agents/` (index: `.agents/MEMORY.md`). Read it +before substantive work. Propose additions as files in `.agents/proposals/`; +trusted memory under `.agents/memory/` changes only through reviewed commits. +Code, tests, and configuration always outrank memory. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..98251b37 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,57 @@ +# Security Policy + +SeedPass is a deterministic (BIP-85 derived) password manager. Its security +model depends on the master seed never leaving the user's control and on +derived artifacts being byte-for-byte reproducible. Detailed internal reviews +live in `docs/threat_model.md` and `docs/security.md`. + +## 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, real seed phrases, or unnecessary personal data — +use throwaway test seeds when demonstrating an issue. + +## Seed-phrase and key custody + +- Never commit, log, print, or transmit seed phrases, master seeds, derived + passwords, TOTP secrets, or private keys — not in code, tests, fixtures, + logs, agent memory, or bug reports. Test vectors must use dedicated + throwaway seeds only. +- Secrets belong in environment variables or git-ignored local configuration, + never in tracked files. +- Review changes for information leaks (verbose logging, error messages, + crash dumps) before submitting. + +## Deterministic artifact rules + +- All derived artifacts (passwords, keys, TOTP secrets) must remain fully + deterministic across runs and platforms; randomness is permitted only for + security primitives (encryption nonces, in-memory keys) and must never + influence derived artifacts. +- Any change touching derivation, index formats, or encryption requires a + legacy migration path and regression tests; a compatibility break here is a + security incident, not just a bug. + +## 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.