factsheet 0.1.0

Per-project memory for coding agents: plain-text facts, injected at session start
# factsheet - project memory for agents

Store: {project_root}/.factsheet/facts.jsonl (opaque; edit only via factsheet).
Root = nearest dir up from CWD with .factsheet/ or .git; else CWD.
No git? Run the first `factsheet add` from the project root to anchor the store.
One fact = one line, self-contained.

## Read

    factsheet                  # whole store, bare `[id] fact` lines (hook injects this)
    factsheet ls               # full lines with #tags and (date)
    factsheet tags             # unique tags with fact counts
    factsheet ls -t deploy,vm  # facts carrying any of these tags
    factsheet ls --stale 30d   # facts not written for 30+ days
    factsheet ls -t ref        # reference facts excluded from the inject
    factsheet find "query"     # top facts by word overlap (locate a fact to fix)
    factsheet projects         # every project with a store (global, self-pruning)

Reserved tag `ref` (push vs pull). Test: would a fresh agent know to
search for this fact at the moment it matters? yes -> ref; no -> keep hot.

  ref (pull):  credentials, keys, IPs, host maps, resource names,
               command recipes, API endpoints, descriptive mechanics,
               diagnostic references
  hot (push):  MUST / MUST NOT invariants, traps with silent failures,
               data-loss and security risks, policy

ref facts are not injected; the inject footer shows their tag counts.
Demote: factsheet edit <id> -t ref,<other-tags> . Promote: retag without ref.
When in doubt keep it hot: a wrongly-hot fact wastes tokens, a
wrongly-ref fact repeats the mistake memory exists to stop.

## Line types (never classify, never re-derive)

    [id] value | check: <cmd>   # use value; run <cmd> only if the value
                                # fails, then `factsheet edit <id>` with the fix
    [id] check: <cmd>           # run <cmd>; never store its output

## Write

Consent gate: every write (`add`, `edit`, `drop`) needs explicit user
approval. Propose the exact fact text and tags, wait for a yes. No
approval -> no write.

Trigger: a repeated error or gotcha a fresh session would hit again.
A fact must (a) change a future action AND (b) contradict defaults or docs.
Facts owned elsewhere (docs, tickets, tool help, global instructions) stay
there. No brain-dump. Tags are the only grouping; run `factsheet tags` before
inventing a new one. `factsheet add` prints `similar:` lines when existing
facts overlap the new one - review them: same fact -> `factsheet drop` the new
id and `factsheet edit` the old one instead.

Choose form at write time: will the value survive a week untouched?
- yes -> store value with -c "<verify cmd>"
- no  -> store only the check line (-c without text)

    factsheet add "value that survives a week" -c "verify cmd" -t tag1,tag2
    factsheet add "durable value, no check needed" -t tag
    factsheet add -c "cmd to run each session" -t tag    # pure check line

## Fact style

Hard limit on text length, enforced - too-long facts are rejected
and the error names the current cap. Limits come from the user's
config file; agents treat it as read-only.
One fact = one rule: a finding with three rules is three facts sharing
a topic prefix ("azure db: ...") and tags; commands go to -c. The
prefix and tags carry coherence, not line length. A card too big to
split is a doc - move it out, keep a pointer fact.

One line, readable with zero context: name the exact
tool, path, flag - never "it", "this", "the config". State the rule,
not the story of finding it; no hedging ("sometimes", "seems").
Cut every word that does no work; a verbatim command or number beats
prose about it. Actionable fact = condition -> action ("X fails -> do Y").
Reuse terms already in the store: one name per thing, or duplicates hide.

    bad:  we discovered deploys can sometimes fail due to caching issues
    good: deploy: run `make clean` first; stale asset cache breaks hashes

## Maintain

Spot a wrong or dead fact -> propose the fix or drop to the user;
apply it only after approval. Inject warns that hot facts outgrew the
threshold -> curate with `factsheet dedup`: it lists over-length facts (split
each into atomic ones) and near-duplicate pairs (merge or drop one);
then drop dead facts and demote lookups to ref. Contradicting facts:
keep the one verified now, `factsheet drop` the loser.

    factsheet edit <id> "new text"    # provided fields replace old; text/check
                                # edits refresh ts, tags-only edits keep it
    factsheet edit <id> -c "new cmd"
    factsheet edit <id> -t ""         # clear tags
    factsheet drop <id>