Start here
How the agent files feedback
A wired agent can record a finding about a blueprint or rcf-lite itself the moment something misbehaves. The record is local and gitignored. Nothing is filed as a GitHub issue until you submit under your own gh login, and preview lets you read the redacted body first.
The feedback surface gives a wired agent one place to record what a blueprint or rcf-lite itself did wrong. The capture is local, the raw log is gitignored, and the only sub-verb that files a GitHub issue is rcf feedback submit. This page covers the shipped shape at rcf-lite 0.28.0. For the full schema of record, see packages/rcf-lite/docs/feedback.md on the rcf-lite repo.
What the agent captures
Every entry names a target and a symptom, with enough anchor and evidence for a triage reader to open the right file.
- Kind and target.
blueprintnames a blueprint the agent applied;corenames a verb or subsystem in rcf-lite itself. - Anchor. An AC, REQ, TAC or ADR id when one applies.
- Symptom class. A closed enum:
docs-mismatch,validate-fails,apply-fails,internal-contradiction,stale-citation,missing-scenario,verb-error,verb-hang,wrong-output,other. - Severity.
blocker,majororminor. - Title and body. Title cap 120 characters; body cap 8 KB of UTF-8.
- Evidence. One or more pointers: a command, a
path:linelocator, an id. - Environment stamp. Harness, rcf-lite version, Node version, platform. A blueprint entry additionally stamps
blueprintVersion,libraryPrefix,libraryRefandresolvedSha(ortarballSha256) so a maintainer can tell which pin the reporter was on.
What leaves the machine
Nothing until you say yes.
rcf feedback addwrites to the local log only.rcf feedback previewis read-only; it renders the redacted issue body and shows a ledger of every substitution the redactor made. It is the operator's read-before-you-send step, not a CLI-enforced gate before submit.rcf feedback submitis the only sub-verb that files a GitHub issue.--yesis the consent contract for non-interactive callers; on a TTY, submit prompts for a yes at the terminal instead. The issue is filed under your ambientghlogin.rcf feedback statusalso touches the network: it runsgh auth statusto warn you when submit would fall through to a local outbox bundle. A failed probe never fails status.
Attachments, screenshots and arbitrary binaries are never attached to an issue.
What is stored locally
The raw capture in .rcf/feedback/entries.jsonl is unredacted, so you (or a later triage tool) can see exactly what the agent recorded before the redaction rules ran. That is why the store is gitignored and why rcf feedback add refuses to write on a project whose .gitignore does not cover .rcf/feedback/. A raw entry may carry absolute paths, hostnames, private IPs, emails, operator identity or secret-shaped strings the redactor would strip on submit. Nothing in the raw log is committed and nothing in it is sent.
Redaction before an issue is filed
Before rendering, preview and submit run the title, body and each evidence pointer through nine redaction rules. Every substitution is recorded in a ledger the operator reads at preview time. Environment stamp fields and destination metadata are not run through the redactor; the whole-body residual safeguard below is the last line of defence against anything a per-field rule missed.
- Paths and remotes. Absolute paths (POSIX and Windows, including paths with spaces), the project root (both the as-typed spelling and its
realpath), and the project's git remote URLs. - Contact and network identifiers. Emails, non-allowlisted hostnames and URLs, private and link-local IPs (v4 and v6,
fc00::/7,fe80::/10), operator identity from the identity seed. - Secret-shaped strings. GitHub tokens, AWS keys,
sk-/sk_live_, Slackxox[abp]-, JWTs, PEM blocks (BEGIN..END),Bearer <token>, and the wholeAuthorization:header line. A line-anchored rule folds the scheme, the credential and any tail together so the token never reaches the body on its own. High-entropy blobs are folded by an entropy-blob backstop. - Vocabulary-key
key: valuepairs. A shared open vocabulary of secret-shaped stems (password,apikey,client_secret,token,bearer,signature, ...) is used by the first-pass redactor, the URL query-parameter scanner and the whole-body residual safeguard, so all three cover the same set. Match is right-bounded at a word edge, sokeywordandauthorsdo not fold.hashfolds only when the value is 16+ characters. The vocabulary is English-only; a non-English key on its own is not recognised, though a shorter one paired with a 32+ character high-entropy value still folds via the entropy backstop. - Vocabulary key labelling a value via any separator. A second pass folds a vocabulary key labelling a value across markdown-table pipes, prose bridges (
password is ...,password was ...,password set to ...), arrows, tabs, hyphens, HTML numeric entities and any other non-:=separator up to 40 characters between key and value. The value has to be 8+ characters and mix at least two character classes among {upper, lower, digit, symbol}, so ordinary prose (the password is required) is left alone. False positives are visible in the ledger and preferred over a labelled value reaching the body. - URL-embedded credentials. A URL's
user:pass@hostuserinfo is dropped before the hostname pass so the host still folds cleanly. Under a known webhook host (hooks.slack.com/services,discord.com/api/webhooks,discordapp.com/api/webhooks,hooks.zapier.com,api.telegram.org/bot) the path after the recognisable prefix is folded to<url-credential>because the token is the path. Query parameters whose name matches the vocabulary above or the presigned-URL set (X-Amz-Signature,X-Amz-Credential,X-Amz-Security-Token,X-Amz-Date,sas,se,sv,sp,access_token) have their values replaced with<url-credential>. Any remaining path or query segment that trips the entropy heuristic is also replaced. - Rendered body cap. 8 KB after redaction. The fingerprint tail is kept so dedupe survives the truncation. The cap is enforced on the fully assembled body (free-form text, evidence rows, environment table, fingerprint twin, consent tail), so an oversized evidence pointer cannot push the rendered body past the cap.
The whole-body residual safeguard
After the nine rules run and dash / control-char / cap normalisation is applied, one last pass runs findResidualSecrets over the whole rendered issue body (and over each bundle file) with multiline patterns. If any residual shape survives (a token buried inside a longer identifier, a multiline PEM block whose first-pass delimiters were folded by dash normalisation, an Authorization: line the primary pass missed), the entry stays pending: preview prints the residual line and pattern, submit refuses that entry and exits 3, and the bundle write is refused fail-closed. The per-field ledger tells you what was stripped; the safeguard guarantees that even if a shape re-appears after per-field redaction and assembly, nothing carrying it leaves the machine.
Store layout
Everything lives under .rcf/feedback/ in the project root:
entries.jsonl: append-only JSON Lines. State transitions (submitted,bundled,deferredUntilSession,discarded) are appended as new lines with the sameid; the reader folds by id and last line wins.state.json: per-session ask ledger.outbox/<ISO-timestamp>-<repo-slug>.md: bundle files written when the submit path cannot land the entry directly. A single-entry fallback appends the entry id (<ISO-timestamp>-<repo-slug>-<entry-id>.md) so two fallbacks in the same second do not overwrite each other; an unresolved destination substitutesunresolvedfor the slug. The SessionEnd hook writes a separate<ISO-timestamp>-session-end.mdalongside as a local reminder; it lists the pending entry titles and metadata, not the full redacted issue bodies you would paste fromprevieworsubmit.
The directory is gitignored via the managed-block aggregator; a fresh rcf init writes the entry into .gitignore automatically. On a pre-upgrade project without the entry, rcf feedback add refuses with a one-line pointer at rcf doctor --fix (or pass --force to bypass).
Sub-verbs
rcf feedback addrecords one entry. Printsrecorded <id> (<n> pending). Nothing sent.on stdout. Exit 0 on success, 2 on usage errors (bad enum, oversize body, gitignore not covering the store), 3 when--kind blueprintand the target does not resolve to a known blueprint. Body cap 8 KB, title cap 120 characters.rcf feedback list [--all] [--json]prints pending entries by default, ascending onrecordedAt.--allincludes every state;--jsonemits the full entry objects. No file writes, no network calls.rcf feedback status [--json]prints counts by status and the environment-driven opt-out state.rcf feedback previewrenders the redacted issue body plus the redaction ledger for an entry. Read-only.rcf feedback submit(with--yes) is the file-and-post path under your ambientghlogin. A new fingerprint files a fresh GitHub issue; a fingerprint that already has an open issue on the target repo gets a compact+1comment on that issue instead of a duplicate. When preflight fails (noghonPATH,ghnot logged in, no access to the destination, issues disabled on the repo, unresolved destination) or the filing call itself fails, submit writes the entry to a local outbox bundle instead. Refuses fail-closed if the residual safeguard finds anything.rcf feedback deferappends adeferredUntilSessionstate line for every currently pending entry, stamped with the current session id. That silences the ask for the current session only; when a different session's SessionStart runs, those entries are requeued and surface again at its next natural pause. To silence the ask for a project entirely, usercf feedback opt-out.rcf feedback discard <id> [<id>...] | --allappends adiscardedstate line for the named entries (or every pending entry with--all). Discarded entries are hidden from defaultlistoutput and excluded from the carry-over ask count.rcf feedback opt-out/rcf feedback opt-insilence or restore the per-session ask by writingrcf/feedback-settings.json. The file is committed to the repo, so a shared project silences the ask for everyone;add,previewandsubmitkeep working underask: falsefor hand-driven flows.rcf feedback hook <stop|session-end|session-start> [--harness <h>]is the harness hook handler.--harnessdefaults toclaude-codewhenCLAUDECODE=1and tocodexwhen anyCODEX_*env var is set; otherwise the flag is required.
Settings file
rcf/feedback-settings.json is written by rcf feedback opt-out and opt-in; it is read by the hook and by rcf feedback status. rcf init does not write the file, so on a fresh project the defaults below apply until you run one of the opt commands. Defaults:
{
"settingsVersion": 1,
"ask": true,
"quietMinutes": 15,
"redaction": { "allowHosts": [] }
}
askgates the Stop hook.falsesilences it;add,previewandsubmitkeep working. Restore withrcf feedback opt-in.quietMinutesis the age threshold on the newest pending entry. A lower value asks sooner; ablocker-severity entry can pass--ask-nowto bypass the age gate.redaction.allowHostsextends the shipped vendor allowlist for the redaction hostname rule.
Hook install
rcf init merges three feedback hook entries into .claude/settings.json and .codex/hooks.json: Stop (timeout 10), SessionEnd (timeout 5) and SessionStart with matcher startup|resume (timeout 5). Each command line is:
npx rcf-lite feedback hook <event> --harness <claude-code|codex>
--bin-path <path> on rcf init replaces the npx rcf-lite prefix with node <path> for pinned-bin deployments. --no-feedback-hooks skips both writes; RULE 17 in the managed instructions block still covers the ask via the fallback path.
rcf doctor --check feedback-hooks diagnoses drift: missing-hook per file per event is fixable with --fix; foreign-hook (an entry whose command names our verbs but whose flags or timeout differ) is refused so a bespoke variant is never silently overwritten.
Environment variables
RCF_FEEDBACK_ASK=0silences the Stop-hook ask.RCF_FEEDBACK_DISABLE=1makesadda no-op that printsfeedback disabled by envand exits 0, without touching the tree. For locked-down environments where even a local log is unwanted.RCF_FEEDBACK_SESSION_IDoverrides the session id stamped on new entries (defaults tounknownwhen the harness does not export one).
RULE 17 in the managed block
The harness block that rcf init writes carries a rule directing the agent to record blueprint and core findings the moment they happen, without interrupting you and without any network traffic. That rule is the belt-and-braces path when the Stop hook is disabled or missing. The block's exact text lives on the Harness block page, and every project keeps a live copy in its own CLAUDE.md or AGENTS.md.
Related
- Wire your agent: install rcf-lite and let init register the hooks.
- Harness block: the operating rules
rcf initwrites into your agent-instructions file, including RULE 17. - Schema of record:
packages/rcf-lite/docs/feedback.mdon the rcf-lite repo. Every claim on this page is a summary of what that document specifies for the shipped shape.