Guardian follows up on translation reviews. It checks trusted feedback against the current source and glossary, applies permitted corrections, and can propose pipeline fixes when a problem keeps recurring. You decide what it may change; humans still review and merge the results.
This is an optional, self-hosted tool, not a hosted service. Each project supplies its own machine, credentials, trusted-reviewer list, and Codex/ChatGPT plan (or explicitly opts into API billing). The operator handles costs, updates, logs, and recovery. Pipeline maintainers receive no credentials or private access.
Start with observe, which records assessments without GitHub writes. Enable
editing only after checking a successful observation run and its configuration.
The rest of this page is the operator reference. Closed-PR remediation and pipeline-prevention work each require their own explicit policy.
The configured mode is a ceiling. A command-line option cannot raise the authority granted by the operator-owned config.
| Mode | Maximum authority |
|---|---|
observe |
Report-only intake, assessment, audit records, and local status. It creates no commits, pushes, comments, or other GitHub writes. This is the default. |
prepare |
Everything in observe, plus validation of eligible value-only replacements in a disposable local checkout. It stores the outcome and a changed-key count in private action state, but retains no patch or reviewable plan. It cannot push or comment. |
apply-owned-translations |
Advance an allowed, Guardian-owned translation PR with validated value replacements, then post one concise status reply. An independently configured closed-PR remediation policy may also create bounded current-base correction PRs ready for review. |
propose-prevention |
Everything above, plus at most the configured number of prevention PRs per poll, shared across repositories, for recurring pipeline defects. It never merges either kind of PR. |
The CLI creates new prevention and historical-correction PRs ready for review
so repository review bots can start immediately. Signing, regression validation,
numeric actor/repository checks, and publication limits are unchanged. Recovery
accepts both ready-created PRs and older drafts with a one-way ready transition;
it never reopens or converts an existing PR. The internal draft ledger names
and max_*_drafts_per_run keys are retained for compatibility and still bound
all new publications. Low-level broker callers retain draft creation by default;
the runtime explicitly selects ready creation. This does not implement automatic
review follow-up on pipeline prevention PRs, nor enable automatic merging.
Review bots may append release notes to a PR description. Recovery still requires every byte of the Guardian-authored body and its evidence marker to match the private ledger. It additionally permits one appended CodeRabbit release-note block of at most 8 KiB, bounded by its standard start/end markers. This suffix is untrusted commentary, not proof of its author’s identity or authority for any edit. Rewritten original text, nested markers, arbitrary trailing text, and oversized annotations remain conflicts; repository, actor, head, and lifecycle checks still apply. The complete remediation body retains its existing size cap.
The Guardian does not merge pull requests, approve reviews, resolve review threads, delete or edit reviewer comments, overwrite an existing remote ref, or broaden its own policy. A human remains responsible for accepting translations and prevention work.
The Guardian treats review comments, repository content, pull-request metadata, and model output as untrusted data. Any of them can contain prompt injection or malformed content. The controller never treats text from those sources as a command, policy change, credential request, or authorization decision.
Authorization comes only from the local Guardian config, which should live outside every monitored checkout. Across intake, assessment, validation, and the final remote-write boundary, the controller enforces:
base_branch);The localization pipeline config and glossary are inputs to validation, not
sources of Guardian authority. The backward-compatible default,
pipeline_config_source: base, loads them from the exact trusted base SHA,
never from the PR head. Their paths must remain inside that trusted tree.
For a project whose pipeline config must stay outside its repository, set
pipeline_config_source: operator. The existing relative
pipeline_config_path then resolves beside the private Guardian YAML. Before
any GitHub or model work, each scheduled or manual poll reads the pipeline
config and its configured (or default) safe relative glossary through
non-following file descriptors and snapshots them into a private per-poll
bundle. The Guardian YAML directory and every bundle directory must be owned by
the current operator with mode 0700; pipeline-config and glossary files must
be current-user-owned, non-symlink regular files with mode 0600. Inputs are
bounded and must be valid UTF-8 YAML or JSON. Unsafe ancestors, absolute paths,
parent traversal, malformed content, and an absent explicitly configured
glossary fail closed. A missing implicit default glossary.json remains valid,
matching pipeline behavior.
The private snapshot cannot change when an operator file is replaced during a
poll. Its deterministic digest enters model evidence and the assessment cache
identity. In both source modes, source-locale strings still come only from the
exact base SHA, and the configured profile source locale must match the
Guardian’s local source_locale policy. A PR that changes these inputs cannot
use its changed versions to authorize itself.
On the translation-correction path, only value-only replacements are eligible. The read-only assessment model cannot add or remove keys, edit a source-locale file, choose a new path or locale, or replace whole files. A stale observation fails closed and is reconsidered on a later run. The separate, opt-in prevention author may change executable pipeline code only within its explicit code/test allowlists and the additional controls described below.
Oversized open-PR correction proposals are applied in bounded batches, never by
raising max_value_edits_per_run. Each run publishes at most that many eligible
value edits; a later poll reassesses the remainder against the fresh PR head.
This also supports a single review comment requesting more edits than the cap.
Partially corrected and wholly deferred comments remain pending, including after
publication-reply recovery. Duplicate targets still reject the proposal before
batch selection; all selected edits retain the normal validation and signing gates.
A zero edit limit disables edits without repeatedly retrying unchanged policy.
Progressive batching applies only to apply-owned-translations and
propose-prevention. prepare retains no patch or changed head, so it keeps its
single-pass bounded validation: an oversized proposal is rejected once under
the current policy, not repeatedly prepared in identical partial batches.
Poll outcomes and the latest Guardian health record expose deferred_value_edits,
deferred_feedback_items, and translation_policy_rejections separately from
failed runs. A successful bounded poll does not mean every correction is finished.
Audit rows use translation_batch_deferred with the actual changed/deferred counts
and published commit where applicable. State schema 12 also records public
explanation delivery and held decisions. Back up the idle database before
upgrading; do not downgrade a schema-12 database.
Private deterministic quality findings retain a source-commit link in signed correction commits. This evidence is separate from reviewer comment links and must match the exact scanned head, or its recorded Guardian publication lineage, repository and GitHub host. Public feedback still requires an exact PR-comment link; a commit link in public feedback does not grant correction authority.
In the two publishing modes, completed open-PR assessments produce bot-labelled explanations at the original review thread. Issue comments and review summaries instead receive a PR comment linking to the source feedback. Explanations distinguish validated corrections, alternatives, already-addressed findings, inapplicable suggestions, deferred work, and maintainer decisions. Applied corrections link to the recorded commit. Threads are never automatically resolved.
Clean CodeRabbit summaries remain in the private assessment audit without public replies when the assessment confirms no applicable correction or maintainer decision. Private prevention analysis continues independently. Unknown summary formats and summaries containing nitpick, outside-diff, or actionable findings retain normal reporting. Previously delivered clean-only summaries are not recreated after operator cleanup; withdrawal notices for other feedback remain enabled.
An interrupted older write can leave a public comment whose delivery was never confirmed locally. Quiet-report retirement preserves that attempt’s payload for audit but does not remove the remote comment; operators must inspect and clean up any such old comments separately.
Public reasons are fixed templates selected by schema-validated codes, not raw model rationale, configuration paths, credentials, or replacement text. An alternative selected to respect the glossary still requires a terminology decision; publishing that correction does not settle the disagreement.
One managed summary comment links to individual explanations and highlights decisions. This is the safe fallback rather than editing PR descriptions: the original CI/translation report, human text, and exact Guardian-generated PR body recovery contracts remain untouched. External edits to a managed comment cause publication to stop rather than overwrite them.
Completed action records (including atomic publication recovery plans) are the
durable explanation intents. Exact public payloads and acknowledgements are
persisted separately. A lost GitHub response is recovered by checking the exact
marker, writer identity, content, and thread; it does not require another model
call or correction. Changed feedback must be revalidated/reassessed before any
new post, and closed PRs cannot receive these open-PR reports. observe and
prepare never publish explanations.
When actionable corrections are pending, Guardian assesses and attempts them before sending old status explanations. A reviewer bot can react immediately to a status reply and change the trusted snapshot; such replies must not repeatedly starve the repair itself. Reporting-only polls still reconcile pending replies without a model call. Every publication retains the same fresh authority checks.
A complete open-PR intake retires pending deliveries for pulls no longer eligible for these reports. Retirement is not a delivery acknowledgement or a policy decision; a reopened eligible pull can reconcile its exact report again. Failed processing records a generic deferred explanation for the next authorized intake, without exposing provider errors or bypassing a quota/authentication circuit.
A recorded decision remains held across model reassessments, PR head movement, and bot replies under the same trusted configuration snapshot. A maintainer must choose the policy, and the operator must deliberately update the governed configuration before reconsideration. This feature does not interpret comments, thread resolution, or merging as glossary-policy authorization. Keep unrelated configuration changes separate from decision resolution and review the next assessment; changing the trusted configuration invalidates the old hold context. If a bounded batch applies part of a glossary alternative, its remaining edits are explicitly reported as human-held. They are not silently discarded, claimed complete, or automatically reconsidered while the policy decision remains held.
guardian status exposes pending explanation acknowledgements and recorded
maintainer decisions alongside reporting health. These are separate from pending
translation edits and last successful poll. A successful correction or poll does
not imply every decision has been settled. Model/session limits, subscription
authentication, retry bounds, signing, and existing repository authority remain
unchanged. Rendering and delivering reports use no additional model session.
Assessment explicitly considers recurring failures, including untranslated source-identical text and lost safety warnings, as well as individual corrections. Candidates must cite trusted feedback and describe a possible regression test; the prevention author must verify any hypothesized root cause against current pipeline code. Empty candidate lists require an explanation in the assessment summary. This is model assessment, not a guarantee that every systemic defect will be detected. Project-specific terminology remains distinct from generic pipeline fixes; legitimate source-identical brand or shared-language terms must not be changed merely to make them different.
Trust is set per repository and locale. Put native human reviewers under
trusted_reviewers and deterministic service accounts under trusted_bots.
Each entry includes its immutable numeric GitHub ID and expected API type. Login
names are display labels only; they never grant authority.
The same rule applies to repository ownership. base_repo_id and each
allowed_head_repositories[].id are authoritative. base_repo is also the
expected current API route and must be updated after a base-repository rename.
An allowed head repository’s full_name is operator-readable routing metadata;
fresh PR authorization follows its numeric ID, so a rename is not confused with
an account that reuses the old name.
Human and bot lists are deliberately separate, but both can be explicit feedback
authorities. A bot whose numeric ID is listed under trusted_bots may authorize
auto-application for that repository and locale; this supports automated review
nitpicks. It never inherits trust from trusted_reviewers, and a human entry
never authorizes a bot with the same display name. Every resulting proposal
still passes the same model-output and deterministic value policy. IDs must be
unique across both lists for a locale. Each operator must replace every example
ID with values read from GitHub’s API.
For each allowed open PR, intake paginates issue comments, review bodies, and inline review comments. Each authorized edit or deletion is a new immutable observation; it is not silently replaced in the audit trail. Feedback outside the configured reviewer/bot and locale allowlists cannot authorize work and is not sent to Codex. The Guardian’s own marked status replies are excluded from authorization and assessment.
Repository visibility is read from GitHub before any model call. A private
repository requires explicit opt-in through private_repo_model_opt_in: true.
Without that opt-in, no private review text or repository evidence is sent to
Codex. Before enabling it, the operator must confirm that their OpenAI account,
data controls, and organizational policy permit the transfer.
The Guardian uses the non-interactive codex exec interface described in the
official Codex documentation.
It runs the assessment with a sanitized evidence directory and a fixed JSON
Schema. A custom guardian_evidence permission profile grants minimal
filesystem reads plus read access to the evidence workspace. The driver uses
--ephemeral, --output-schema, --json, --skip-git-repo-check,
--ignore-user-config, --ignore-rules, --strict-config, and
--ask-for-approval never. Review text remains data rather than shell input or
a command-line argument.
Codex receives no GitHub write or signing credential. Its tool processes inherit no model credential, and it cannot edit the monitored checkout. The controller rejects missing, invented, duplicated, oversized, non-UTF-8, or schema-invalid output. It then reconstructs locale, feedback identity, and source values from trusted controller data and independently applies every policy check. Structured output constrains parsing; it does not make model output trusted.
Every Codex invocation and focused prevention test runs in a new process
session with inherited CPU, file-size, descriptor, and supported process-count
limits. On Linux, the Guardian additionally requires a fresh cgroup-v2 leaf for
each bounded invocation. It joins the direct child before exec, activates the
kernel’s recursive cgroup.kill control on every completion path, waits for
populated 0, and only then removes the leaf. The leaf’s maximum depth and
descendant-cgroup count are both zero, so a child cannot leave empty nested
cgroups behind. This includes a descendant that calls setsid() or setpgid()
and escapes the original process group.
The operator’s Linux service or container cgroup must be delegated so Guardian
can create those transient leaves. guardian doctor performs a
real create/join/kill/remove canary and fails closed when cgroup v2, delegation,
or cgroup.kill is unavailable. The cgroup is a lifecycle boundary, not a
filesystem sandbox: the Codex and prevention-test sandbox canaries also require
that an untrusted tool cannot open the parent cgroup.procs for writing. That
denial prevents a same-user descendant from migrating out of the leaf.
macOS has no cgroup-v2 equivalent. There the resource limits, process-group cleanup, Codex permission profile, and operator-supplied prevention sandbox remain in force, but process-group cleanup alone is not a hard boundary against a deliberately detached descendant. Operators who require kernel-enforced descendant teardown should run the Guardian in a Linux container or VM whose outer runtime also tears down the complete container on exit.
The shipped Guardian default is gpt-5.6-terra with reasoning effort high.
Terra is OpenAI’s balanced intelligence/cost model and currently uses about
half Sol’s Codex token-credit rate; high retains deliberate reasoning for
semantic review while every proposed action remains deterministically checked.
See the
official GPT-5.6 Terra model reference
and Codex rate card. Model and
effort remain explicit operator policy: use Sol/max only when representative
evaluations justify the additional plan allowance or API cost.
localize guardian deliberately does not run the translation plugin loader.
An explicit --plugin argument is rejected, while
LOCALIZE_PLUGIN_MODULES and installed localize.format_adapters entry points
are ignored. This prevents project plugin code from running in the
credential-bearing Guardian process. Only the package’s built-in registered
adapters are available; a trusted-base pipeline config that requires a custom
adapter fails closed during a run. doctor reports the adapters already
registered in that isolated process, but it does not claim custom-project
compatibility.
Prerequisites:
localize package;Create an operator-owned config from the report-only example:
GUARDIAN_CONFIG="$HOME/.config/localize/guardian.yaml"
install -d -m 700 "$HOME/.config/localize"
localize guardian init --config "$GUARDIAN_CONFIG"
init refuses to overwrite an existing file. Compare its output with
examples/guardian.config.yaml, then set the
repository, owned PR/head identities, branch and path constraints, locales, and
numeric reviewer IDs. Keep mode: observe until doctor, a manual run, and the
local audit output are clean.
The Guardian config is strict: unknown fields, duplicate YAML keys, unsafe
relative paths, duplicate identities, and malformed limits are errors. Never
load it from a pull-request head or let a monitored repository modify it.
Use pipeline_config_source: operator only when the pipeline config and
glossary are stored under the same private config directory as described
above; base remains the default.
The default, codex_auth_mode: chatgpt, consumes the operator’s Codex access
and ChatGPT plan allowance, not metered API billing. It can still consume
purchased ChatGPT/Codex credits when the operator’s account or workspace allows
them, so it is not a guarantee of zero marginal cost. First create the config,
then perform one device login into the dedicated codex_home:
localize guardian login --config "$GUARDIAN_CONFIG"
guardian login forces forced_login_method="chatgpt" and
cli_auth_credentials_store="file", and Codex refreshes the cached login when
needed. The Guardian requires the dedicated directory to be owned by the
current user with mode 0700, and its non-symlink auth.json to be a regular
user-owned file with mode 0600. Treat that file as a password: do not copy,
publish, back it up to a shared location, or commit it. The generated scheduler
points at the same private login, so no interactive login is required during a
scheduled poll. See the
official Codex authentication guide
for the distinction between ChatGPT and API-key authentication.
The login, status check, assessment, and prevention-author processes receive a
minimal environment. In particular, inherited CODEX_API_KEY and
OPENAI_API_KEY are removed, while the forced authentication method prevents
an accidental switch from plan allowance to API billing. Codex tool processes
receive neither the subscription credential directory nor a model API key.
API-key mode is an explicit opt-in. Set codex_auth_mode: api-key, remove
codex_home, configure runtime.codex_api_key_command, and configure both USD
limits. In API-key mode, the self-hosted Guardian does not accept an ambient API
key. Instead it invokes the configured operator-owned helper just in time, injects
CODEX_API_KEY only into the bounded Codex process, and uses an ephemeral Codex
home. The helper must print one API key to stdout and nothing else. Keep it
outside monitored repositories and backed by an OS secret store.
GitHub secrets are also never stored in Guardian YAML, launchd property lists,
generated wrappers, state, model evidence, or logs. Configure an OS-secret-store
token helper before installation. The helper must print one repository-scoped
token to stdout and nothing else; prefer a short-lived token when the provider
supports one. It is invoked as an argv array with shell=False, a timeout, and
redacted errors. The token is retained only in memory for the bounded Guardian
operation; temporary Git askpass material is removed afterward. Write scopes
are used only for an authorized translation branch update and status reply, an
explicitly configured prevention branch and PR, or an explicitly
configured current-base remediation branch and PR. Historical remediation
publication is available in apply-owned-translations or
propose-prevention; prevention publication is available only in
propose-prevention.
On macOS, either helper can retrieve its credential from Keychain. Keep helpers outside monitored repositories, owned by the operator, and executable only by that user. Do not put a token literal in a helper, environment file, or scheduler argument.
OpenPGP is the backward-compatible default. Keep signing_format: openpgp, set
signing_program to the trusted GPG executable, and set signing_key to the
full 40- or 64-hex fingerprint (optionally suffixed by ! for an exact GPG key
selector). Existing OpenPGP installations need no migration.
Agent-backed Git SSH signing is an opt-in alternative:
runtime:
signing_format: ssh
signing_program: /usr/bin/ssh-keygen
signing_key: SHA256:REPLACE_WITH_EXACT_PUBLIC_KEY_FINGERPRINT
signing_public_key: /absolute/path/to/guardian-signing-key.pub
signing_key is the exact unpadded SHA-256 fingerprint printed by
ssh-keygen -l -E sha256 -f <public-key>. The public-key file must contain
exactly one supported key. It must be an absolute, non-symlink regular file,
owned by the operator or root, not writable by group or other users, and have
one link. Its ancestors must also be trusted. DSA, malformed or multiple keys,
RSA keys below 3072 bits, and a fingerprint mismatch fail closed.
The Guardian never reads or stores an SSH private key. Before external poll
work it copies the validated public key into a private bounded snapshot and
derives a one-key allowed-signers file. Git selects that frozen public key and
asks the existing ssh-agent for the matching private operation. The validated
agent endpoint must have a private 0700 parent. If a higher macOS system
directory is root-owned but group-writable, Guardian hard-links the exact socket
inode into the private signing snapshot and verifies both names before use;
ordinary mutable ancestors still fail closed. SSH_AUTH_SOCK is passed only to
the git commit subprocess—not to Codex,
credential helpers, repository fetch/push, signature verification, or focused
tests. The resulting commit is verified against the one-key trust file both
after creation and immediately before publication.
An existing GitHub SSH signing key can therefore be reused when its private
half is already available through the operator’s agent; only its public half
and exact fingerprint enter config. Register the public key as a GitHub signing
key as usual. On macOS, Keychain can remember the private key, but it must also
be available to the launchd-visible agent (for example via
ssh-add --apple-use-keychain). Do not place a private-key path, private key,
or a literal agent-socket path in Guardian YAML or a launchd property list.
Run guardian doctor from the same user/session used by the scheduled job; its
real sign-and-verify probe catches an unavailable agent or key before writes
are enabled.
Interactive runs may resolve tools from the operator’s PATH. Before staging a
LaunchAgent, set runtime.codex_executable, runtime.git_executable,
runtime.github_token_command[0], and—only in API-key mode—
runtime.codex_api_key_command[0] to actual executable absolute paths. A write
mode also requires an absolute runtime.signing_program. These paths must be
non-symlink, operator- or root-owned executables with trusted parent directories;
interpreted helpers must use an absolute interpreter in their shebang. In
particular, an npm shim or script using #!/usr/bin/env node is rejected: point
codex_executable at the package’s platform-native Codex binary instead.
Every custom credential command must contain exactly one argv item naming the
inspected helper. The sole multi-item exception is the exact GitHub CLI command
gh auth token. Python, Node, shells, nice, nohup, and other interpreter or
dispatcher programs are not accepted as argv[0] with an unchecked helper
script in a later argument. A credential helper may itself be an executable
script, because Guardian inspects that script and its absolute shebang
interpreter chain; the shebang itself must contain only the interpreter path,
without flags or other arguments. guardian doctor resolves interactive
command names and validates each resulting executable before invoking any of
them. guardian install additionally requires absolute configured paths. Every
due scheduled run checks the executable and its interpreter chain again before
credentials or repository data are used, so a background process cannot
silently pick up a replaced binary from a changed PATH.
A model-credential-helper failure in API-key mode or any Codex authentication failure opens the poll’s authentication circuit, as does a GitHub credential-helper or API authentication failure. The circuit stops later repository and model work in that poll. Non-authentication GitHub transport, API, and policy failures fail closed as ordinary repository or candidate failures; later policy-scoped work may still be attempted.
An exhausted ChatGPT allowance, insufficient Codex credits, or a hard API billing quota opens a separate model-capacity circuit. The Guardian does not immediately retry that non-recoverable condition or start model work for later repositories in the poll. It records only a redacted health outcome; inspect the provider account for the reset time or billing decision.
localize guardian login --config "$GUARDIAN_CONFIG"
localize guardian doctor --config "$GUARDIAN_CONFIG"
localize guardian run --config "$GUARDIAN_CONFIG"
localize guardian status --config "$GUARDIAN_CONFIG"
doctor makes no monitored-repository or GitHub writes and redacts credential
material. It checks the config, state directory and process-lock safety without
acquiring an active poll lock, the Codex executable and schema,
the dedicated ChatGPT login or API-key helper, GitHub credential helper,
GitHub identity, repository visibility, signing setup, and built-in adapters
registered in the isolated Guardian process. Target-project adapter
compatibility is checked later from the exact base checkout during a run.
In either write mode, every repository must name a top-level
publication_actor, and the same read-only probe resolves /user once. That
credential’s immutable numeric ID and API type must match every repository’s
actor. If a positive publication cap enables nested remediation or prevention
draft creation, each enabled nested actor must be the same identity;
configurations that would require different actors fail closed. Neither the
token nor mutable login is printed.
The publication actor must have GitHub API type User. Use a narrowly scoped
personal access token for a dedicated machine user, or another user token that
GitHub supports on
GET /user.
A GitHub App installation access token writes as a Bot but cannot satisfy
this user-identity proof, so installation-token publication is intentionally
rejected. Supporting it would require a separate installation-identity
protocol. This restriction applies only to publication; review feedback from
explicitly configured bots remains supported.
For apply-owned-translations and propose-prevention, set
runtime.signing_key explicitly (and runtime.signing_public_key for SSH).
The doctor creates an ephemeral local commit and proves that exact key can sign
and verify with global and system Git config disabled—the same isolation
boundary used for Guardian commits. For SSH it also uses the private one-key
allowed-signers snapshot and withholds the agent socket from verification. A
global user.signingkey is deliberately not accepted.
Each operator-run guardian run executes one finite poll.
limits.run_timeout_seconds is one elapsed-time budget measured against a
monotonic deadline for active work, not a fresh timeout for each repository,
request, page, retry, or subprocess. Setup snapshots and recursive workspace
scans check the same deadline; GitHub streaming and pagination recheck it between
chunks and pages; credential helpers, Codex, prevention tests, signing inspection,
and Git subprocesses receive no more than the remaining budget. Expiry stops new
work and prevents later remote mutations. Bounded SQLite finalization, recovery
bookkeeping, process teardown, temporary-file cleanup, and lease release may
finish after expiry so timeout handling cannot strand unsafe or misleading state.
status shows the last completed feedback run,
component health, pending feedback revisions and historical hydration retries,
aggregate action and remediation lifecycle counts, and current UTC daily model
calls (completed plus active or unknown reservations) without printing raw
review bodies or secrets. In API-key mode it additionally shows committed API
cost (settled cost plus active or unknown reservations).
Failed polls also print a short stderr alert pointing to guardian status.
That command shows the latest private failure ID, timestamp and structured
diagnostic: poll ID, available source PR/run identity, operation, exit or HTTP
status, fixed reason codes and pipeline code locations. At most 32 diagnostics
are appended per poll to the existing private audit database. Unknown errors
remain unclassified with code locations; raw stderr, exception prose, command
arguments, credentials and absolute paths are never stored in these records or
copied into public replies. A later failure does not replace the last-success
timestamp. Desktop notifications depend on the operator’s scheduler wrapper.
Rejected prevention regression proofs record red_green_mismatch with the
base and patched outcomes (passed, failed, error, or timed_out) and
bounded numeric exit codes. This distinguishes an already-green baseline from
a failing candidate or test-runner error without retaining test output. The
requirement that tests fail on the base and pass on the candidate is unchanged.
Two bounded, redacted operator worklists expose durable recovery state under the same exclusive poll lock:
localize guardian remediation list --config "$GUARDIAN_CONFIG" --limit 100
localize guardian history-retry list --config "$GUARDIAN_CONFIG" --limit 100
remediation list is the detailed provenance and lifecycle surface. It orders
active attempts before terminal local history and explicitly reports when the
requested attempt bound or the per-draft coverage bound truncates output. For
each bounded result it prints the draft key and branch-identity version; exact
target, push, ref, and commit identities; local publication phase; PR number
and canonical URL when present; terminal resolution; the latest remote
observation and its state/draft/merged/base/time fields; and the exact source
PR, policy, revision, coverage reason, linked draft keys, and whether that
coverage is currently effective. It never prints review-comment bodies.
status intentionally keeps this information aggregated.
remediation quarantine requires
--acknowledge-terminal-local-skip and atomically appends an
operator_quarantined resolution plus terminal coverage for every exact source
linked to the listed local attempt. It is an explicit terminal local skip, not
an inference from remote absence, and does not change its remote branch or pull
request.
history-retry quarantine requires the exact repository name and numeric ID,
policy digest, pull ID, PR number, and the same acknowledgement. It is a
deliberately permanent source-PR veto under that policy digest: later comments
on that PR are ignored while the policy is unchanged, and changing the policy
makes the PR eligible again. Neither command edits, closes, reopens, comments
on, or otherwise changes GitHub state.
Review at least one real report-only run before moving to prepare. The
status command shows aggregate action state, not the prepared key count or a
diff. Because the validated checkout is disposable and no patch is retained,
use a controlled test PR and the configured deterministic limits before
enabling apply-owned-translations; do not treat prepare as a reviewable diff
preview.
In apply-owned-translations, the Guardian writes only to a PR that still
matches every configured ownership constraint. It creates a signed, normal
descendant commit and advances the existing head without force. It never creates
an unrelated project runner or commits project-specific policy to this pipeline
repository.
Every repository in either write mode must configure a top-level
publication_actor. It is the exact GitHub actor that publishes ordinary
translation commits and authors status comments, identified authoritatively by
numeric ID and API type User; its login is display-only audit metadata. This actor
is deliberately independent of allowed_pr_authors, which controls which
existing PR owners may have their branches advanced, so the publication actor
does not gain PR-ownership authority by being configured. The write broker
authenticates the credential against the actor before repository and
pull-request access, then checks it again around the commit push and
status-reply write boundaries. An identity mismatch or mid-operation rotation
fails closed.
After the new head is confirmed, it may post one idempotent, bot-marked, commit-linked reply. The shape is deliberately modest:
🤖 Localize Guardian: Applied a validated translation-only correction in the linked commit. The review thread remains open for reviewer confirmation.
The hidden idempotency marker prevents duplicate replies after a crash, but the marker alone is never trusted. Recovery accepts it only when the numeric actor ID/type, full canonical body, comment ID-derived URL, publication evidence, and current PR authority all match. A foreign, altered, or duplicate marker fails closed instead of suppressing a genuine reply. A reply claims only what the deterministic checks and confirmed commit establish.
Closed-PR processing is disabled unless a repository has an explicit
closed_pr_backfill block. Each poll finishes the open-PR phase across the
configured repositories first. Closed history is then traversed newest first in
durable scan cycles. A cycle freezes both its UTC start as an upper bound and
its lookback_days cutoff as a lower bound. Every later poll restarts at GitHub
page 1 and skips exact pull ID/number pairs in an append-only per-cycle seen set;
it does not persist a mutable pagination position as discovery progress. Before
reporting the cycle complete, the reader performs a second identity-only
traversal and requires it to contain no uncovered eligible pull. This catches
page shrink, insertion, and equal-timestamp reordering that the two traversals
actually observe.
GitHub’s REST listing is not an atomic snapshot. Completion therefore requires a quiescent, bounded discovery-and-confirmation pass; it is not a claim that no concurrent mutation could occur outside the two observed traversals. A later cycle rechecks the window and can discover such a change.
Each discovery or confirmation traversal is limited to 100 numeric pages and
10,000 list entries. If either traversal cannot reach the frozen cutoff or the
end of the list within that ceiling, the poll fails visibly and keeps the cycle
incomplete; narrow lookback_days before retrying such a high-volume window.
Within that ceiling, while its dependencies succeed, and once the listing is
quiescent long enough for confirmation, repeated polls cover the full frozen
window even when earlier entries are ineligible or already complete. Hydration
remains separately bounded to max_prs_per_poll eligible pull requests for that
repository. The strict configuration ranges are 1–3650 days and 1–100 pull
requests per poll.
A non-authentication GitHub failure while hydrating one pull is retried up to three times immediately. After the third failure, the error is recorded and the identity is skipped for the rest of the current cycle, so one persistently malformed pull cannot starve older history. The durable pending retry is prioritized on later polls independently of the discovery window until it succeeds or an operator explicitly vetoes it. Authentication failures abort the poll and do not advance the affected work.
The frozen upper bound and lookback cutoff govern discovery of new closed-PR
evidence only. At most one durable pending branch-only remediation batch is
selected for direct reconciliation in a repository poll. Its exact source pull
identities must fit within max_prs_per_poll, but reconciliation uses immutable
stored evidence and the exact remote branch/PR identity; it does not claim to
rehydrate every source before inspecting an already-created remote artifact.
Direct recovery ignores the discovery window, so durable pending work or an
already-published branch cannot age out before reconciliation. When a fresh
candidate is required, the whole source group enters the durable priority
hydration path ahead of ordinary discovery, even when those sources are now
older than lookback_days; each source must still match its exact identity,
remain closed, and satisfy current policy and trust eligibility.
If any recovery source cannot be hydrated after its three immediate attempts,
the whole group is deferred for the rest of the current cycle and no partial
candidate is published. This temporary deferral is not the explicit,
terminal-local-skip remediation quarantine action. A persistent operator-only
conflict likewise gets only this bounded recovery path before its sources
advance for the current cycle, allowing older history to continue. A later
cycle can reconsider the batch. Malformed,
ambiguous, duplicate, or mismatching remote PR metadata fails closed and remains
visible to the operator. This deliberately favors publication safety and
backlog fairness over automatic liveness.
After a cycle reaches the cutoff or end of the closed list, the next poll starts
a fresh cycle at the newest page. This periodic rescan can discover an edit or
deletion of exact authorized feedback even when the closed pull request’s head
SHA and top-level updated_at did not change. Feedback authority is a
point-in-time poll snapshot: an edit or deletion observed by a later scan causes
a recheck, but cannot retroactively revoke a remote mutation that has already
begun. Untrusted comment churn and other unrelated update noise do not
invalidate a completed assessment. Both eligible merged and unmerged closed
pull requests are covered; the same configured PR, head-repository, head-owner,
branch, reviewer/bot, and locale authorization still applies.
A historical pull request and its review feedback are evidence only. The Guardian materializes historical revisions through a read-only checkout and never applies or publishes a historical branch. It separately captures the configured repository’s exact current base SHA and builds fresh current source and target evidence. A historical correction is actionable only when the reported defect independently exists on that current base and the proposed value passes today’s deterministic localization policy. This rule is the same for merged and unmerged history: an old comment cannot authorize a stale or unrelated change. If the finding is already fixed or otherwise obsolete on the configured current base branch, the Guardian records a terminal no-action checkpoint and publishes nothing. Compatible current-base fixes may share one batch; conflicting proposals for the same target, ambiguous evidence, and other unsafe cases remain deferred.
An authorized, still-valid finding that is uncovered and selected for remediation is published only through a new bot-marked, ready-for-review correction PR against the configured current base. That PR contains a signed commit and links to the closed source PR and validated feedback. The Guardian leaves the historical PR and its branch untouched. This translation correction is separate from any optional pipeline-prevention proposal.
observe and prepare perform no GitHub writes for closed-PR work. observe
records the bounded assessment and completion checkpoint. prepare may also
validate eligible replacements in the disposable current-base checkout, with
the same non-reviewable local outcome described above. Historical recurrence
candidates may contribute to prevention analysis in propose-prevention, but
that remains subject to the separate prevention policy and publication cap.
A nested remediation policy may remain configured while either read-only mode
keeps it dormant; changing mode is the authority ceiling and does not require
editing the repository policy.
Publishing a historical correction requires all of the following: mode
apply-owned-translations or propose-prevention; an explicit nested
closed_pr_backfill.remediation policy; a positive
max_remediation_drafts_per_run; and the write-mode signing and credential
setup. No prevention block is required in apply-owned-translations. Keep
max_remediation_drafts_per_run: 0 as the report-only and remediation
kill-switch setting; zero is also the schema default. The Guardian combines
compatible current findings into at most one remediation batch per repository
per poll.
max_remediation_drafts_per_run is a separate global per-poll cap shared across
repositories; it does not increase model-call demand because the history
assessment already produced the candidate.
The remediation policy names one exact numeric-ID push_repository, a
push_branch_prefix, and one typed numeric-ID publication_actor. The
publication actor must have API type User and must be the same identity as the
repository’s top-level ordinary publication actor. It is independent of
allowed_pr_authors, which grants authority to advance existing PR branches.
The push repository must already appear in
allowed_head_repositories, and allowed_branch_globs must contain the
literal push_branch_prefix followed by *; a broader pattern alone is not
enough.
The actual generated branch—the prefix followed by a deterministic 64-character
lowercase hexadecimal identity—is checked against the allowlist again at
publication time. Use a dedicated ordinary Guardian-owned head scope such as
localization/guardian-remediation-*, and ensure the GitHub credential can
create the resulting pull request. An unexpected existing ref, repository
identity, or branch fails closed.
Every remediation broker session resolves the credential’s authenticated
GitHub actor. Its immutable numeric ID and API type must match the configured
publication_actor, and any created or recovered pull request must name that
same actor as its author and retain the exact generated title and body. The
publication actor’s login is a display and audit label only; an actor change,
rewritten draft text, or a different allowlisted author fails closed.
For an actionable batch, the Guardian revalidates the exact current target base
and push repository, creates a signed commit on the deterministic new branch,
and opens a new bot-marked pull request ready for human and automated review. The exact
[Localize Guardian bot] title prefix and body text identify it as
bot-generated; this marker is not a GitHub label. Before creation it performs a
coherent sequential pass: after local preparation it rechecks the destination
actor, repository IDs, base SHA, candidate branch, and duplicate-PR state, then
revalidates exact source authority as the final remote observation before the
POST. GitHub’s independent REST resources cannot provide an atomic snapshot;
later changes are detected by the next bounded poll and never make an earlier
observation retroactively atomic. It never reopens, edits, or comments on a
closed pull request, never advances its branch, and never merges the remediation
draft.
Append-only publication phases, the deterministic branch, an embedded evidence
marker, and preserved private durable state provide crash recovery without
creating a duplicate branch or draft. Recovery requires the canonical GitHub
URL, publication actor, head and base identities, candidate commit,
maintainer_can_modify: false, exact generated title, and full generated body
including the embedded marker, except for the bounded untrusted annotation
described above. Current open-draft, open-ready, closed-unmerged,
and merged states are accepted when all of that metadata remains exact;
malformed or rewritten metadata and ambiguous or duplicate remote identities
fail closed. The Guardian never rewrites or reopens the PR.
Each reconciliation appends an exact, not_found, or conflict remote
observation to the private ledger. An exact merged observation and its terminal
merged resolution are recorded atomically so lifecycle and coverage cannot
disagree. not_found means the bounded exact lookup completed without a match;
authentication, transport, and malformed-response failures remain failures and
never manufacture absence.
An already-created exact PR remains recoverable after ordinary target-base advancement. A correction PR that a maintainer closes without merging is a human veto and continues to cover its exact edits, so the Guardian records the closed lifecycle and does not recreate the same correction unchanged. When a correction is merged, its draft-backed source coverage becomes ineffective. If the same defect later recurs on a newly validated current base, a new coverage generation and a distinct remediation attempt may be created.
New remediation branch identities use version 2 and bind the exact remediation policy digest as well as the attempt’s immutable inputs. This prevents a policy change from colliding with a branch left by an older attempt. Rows migrated from version 1 retain their original identity calculation and remain recoverable. If evidence or the target base moves before a branch-only attempt has an exact PR, the Guardian marks that local attempt abandoned, leaves any remote branch untouched, and durably retries its source group. Fresh validation can then create a distinct attempt; no overwrite or branch deletion is used. Unexpected remote content or identity still defers instead of being adopted.
Deduplication is semantic rather than tied to a comment revision. An exact edit is identified by path, key, current source value, expected target value, and proposed target value; its target identity is the path-and-key pair. An exact edit covered by an open or human-closed-unmerged Guardian correction PR is removed from a mixed batch, while uncovered edits may proceed. Merging that PR ends its draft-backed suppression, allowing a later independently revalidated recurrence to receive a new coverage generation. A different edit aimed at the same target identity conflicts and is deferred instead of opening a competing PR. Pending exact edits proceed only through their grouped, bounded recovery path.
Discovery progress is also append-only and compare-and-swap protected for the exact repository identity and policy digest. A stale concurrent progress writer fails closed. A crash before an exact pull identity is marked seen safely rehydrates it on the next restart-from-page-one pass; immutable completion checkpoints keep already-finished model work idempotent. Completion binds the pull identity, relevant pull and changed-file evidence, canonical current source and target content, exact authorized feedback revisions, authority scope, and policy digest. Editing or deleting an authorized reviewer/bot item causes a recheck after a later scan observes that revision, while unrelated or untrusted comment noise does not. Changes to the Guardian policy or to the trusted pipeline config-and-glossary bundle—whether sourced from the exact current base or the private operator snapshot—also start an independent scan and make prior work eligible for reassessment. Unchanged completed work is skipped within a cycle.
Repeated feedback can indicate a one-off translation problem, project policy, pipeline validation defect, prompt weakness, or an ambiguous case. The model may classify a recurrence candidate, but it cannot modify the running installation.
With propose-prevention, prevention authoring happens in a separate disposable
workspace without GitHub write or signing credentials. A prevention change is
eligible only when it is within the configured pipeline paths, cites immutable
feedback evidence, and includes a focused regression test that is failing on the
base revision and passing with the draft. The controller runs each configured
test argv with a minimal, credential-free environment and prepends the exact
operator-supplied sandbox_argv_prefix. This field is deliberately a one-item
argv containing one absolute, directly invoked sandbox-wrapper executable. Put
the confinement policy inside that inspected wrapper; a policy or helper-script
path supplied as another unchecked prefix argument is rejected. Before every
focused command, a runtime probe must be able to read and
write generated paths inside the test workspace
while reads and writes of generated paths outside it are denied. It also
requires denial of an AF_INET loopback bind and a connection to a live parent
loopback canary, plus denial of a filesystem AF_UNIX canary connection when the
platform supports it. On Linux it also requires denial of a write-open on the
parent cgroup’s cgroup.procs, which would otherwise let a same-user test
process leave its recursive kill scope. A failed probe rejects the prevention
candidate. This focused probe does not prove the policy’s behavior for every
host path or network route; the operator still owns and maintains the OS sandbox
policy.
The parent Guardian process must be allowed to create those local canaries; a
host policy that blocks their creation also fails prevention closed.
A regression proof only shows that the new rule fires on its own fixture. Before
publication, the controller therefore also measures the candidate on real data.
It copies the real target localization files of the source pull request (the
exact head checkout used for assessment, the trusted base source files, the
operator pipeline profile, and a controller-computed base-to-head diff) into two
fresh snapshots of the prevention base: one with base code and one with the
candidate. Inside the same sandbox wrapper, probe, and timeout as the focused
tests, the Guardian’s own Python runs each tree’s
localize.translation_quality_gate entry point on that data. Closed-PR
prevention measures the current base’s real files for the same paths without a
diff. The candidate is rejected when it raises semantic plus source-identical
findings by more than limits.max_new_real_data_findings (default 5), with or
without a new blocking reason. A narrow rule that adds a blocking reason with at
most that many new findings, such as one that catches the reported defect,
passes, as do fewer or unchanged findings. A missing corpus, gate error, malformed report, or timeout also rejects
the candidate. Rejections are recorded like failed regression proofs in the
private failure ledger (stage real-data-impact, a reason code, and base and
candidate finding counts) and never publish a branch. The sandbox policy must
therefore also permit the Guardian’s Python and its installed dependencies.
The author prompt states this bound, so narrow rules are preferred.
Exact Git checkouts do not contain ignored project virtual environments. Every
focused_test_argv should therefore start with an operator-controlled absolute
interpreter or test executable outside the repository. The sandbox policy must
permit that executable, the Guardian’s Python used by the probe, their required
runtime libraries, and the disposable workspace—without granting broader host
or network access.
The Guardian pushes only the bounded signed branch needed to open a pull
request ready for review; it does not merge or deploy that proposal. Immediately
before a branch push or draft-creation POST, it checks the live poll lease and
consumes a non-refundable per-poll publication slot. A lost response therefore
does not make that slot available to another prevention mutation. Runtime
defaults cap prevention at one draft publication workflow across the entire
poll, shared by all repositories and feedback runs. Despite the configuration
key’s max_prevention_drafts_per_run name, the counter is not reset per feedback
run.
limits.max_prevention_drafts_per_day (default 1) adds a durable UTC-day cap,
so frequent polling cannot open several prevention pull requests per day. The
same boundary records a slot for the candidate in the local ledger before its
push or POST. Slots are never refunded: an interrupted or ambiguous publication
still counts for that day, while recovery of that same candidate reuses its
slot. When the day’s slots are used, new candidates defer before any model call.
The report-only example pins the cap to zero. propose-prevention always requires
an explicit prevention block for every monitored repository. A zero cap is a
prevention-publication kill switch, per run or per day: recurrence candidates are
skipped, although that mode still retains the translation-write authority
described above.
The prevention target may be a different repository from the monitored
translation project. The prevention block pins target and push repositories by
full name and numeric ID, the exact target base branch, the push branch prefix,
a typed numeric-ID publication_actor, code/test path allowlists, and focused
test commands. The actor login is mutable, human-readable audit metadata; the
exact numeric ID and GitHub User type grant authority. Every prevention REST session
authenticates GET /user and fails closed unless that identity matches, and a
created or recovered pull request must have the same author identity. The
nested actor must also match the repository’s top-level ordinary publication
actor so one poll never changes GitHub identity between write paths. Every
block must state private_target_model_opt_in. If the exact target base is
private, its code is sent to the authoring model only when that field is true;
use false for a public target. The monitored translation repository’s
private_repo_model_opt_in governs its review evidence and does not grant
consent for a different private prevention target. If both are private, both
opt-ins are required.
Prevention policy collections have finite parser and runtime bounds: at most
100 code globs, 100 test globs, 64 focused commands, 256 arguments in each
focused command, and exactly one sandbox-wrapper executable in the sandbox
prefix. Every string in those collections is at
most 4096 UTF-8 bytes, max_changed_files is at most 100, and
push_branch_prefix must leave 77 characters for the generated
<base-prefix>-<evidence-hash> identity inside a 255-character branch name.
The canonical source-policy and maximum test-result attestations must each also
fit 512 KiB, so a configuration that combines many individually maximal strings
can still fail closed before a model or test starts.
Codex output may contain at most 100 recurrence candidates with at most 100
evidence feedback IDs each. Newly generated prevention titles are at most 120
Unicode characters and 256 UTF-8 bytes; bodies are at most 60 KiB. When a
human-facing evidence, path, or command list would exceed its section budget,
the body includes a deterministic omitted-item count and full-list fingerprint
instead of cutting through a Unicode character or Markdown item.
Do not use prevention PRs for project terminology or locale style that belongs in the consuming project’s own config or glossary.
An ordinary prevention-draft failure or exhausted draft slot does not block an otherwise authorized correction on an open translation PR. The signed correction and pending prevention work are recorded separately; later polls retry prevention without repeating the correction. Authentication, quota, lease, source-authority and publication checks still stop work at their respective boundaries. A published correction is not evidence that its prevention PR succeeded: inspect the poll’s prevention failures and deferred counts as well. Private failure diagnostics retain the underlying adapter stage and reason, not raw stderr or credentials.
Prevention recovery also requires the canonical GitHub URL; exact generated
title and Guardian-authored body including its marker; exact head, base, and candidate; and
maintainer_can_modify: false. Ready-created PRs, untouched legacy open drafts,
their one-way draft-to-ready transition, and a terminal close-unmerged from either
draft or ready state are accepted. A reopen, redraft, rewritten metadata, or over-bound
event history fails closed and is never adopted as Guardian-owned state.
The Guardian keeps local SQLite state. Each authorized feedback content change, and each observation of that feedback against a distinct PR head/base revision, becomes a new immutable revision tied to repository, PR, feedback object, author numeric identity, body hash, head SHA, and base SHA. Runs, terminal actions, health, recorded token usage, and recorded cost remain auditable across restarts. Publication phases and marked replies have dedicated reconciliation and deduplication records.
This is not whole-run exactly-once execution. A successful assessment is cached against its exact evidence, head/base revisions, model, and effort before its call completes in the ledger. A process death while a call is in flight leaves that reservation committed. Without a cached result, a later run can repeat an ambiguous model attempt and consume another call slot. In API-key mode it may also incur another charge. Prevention authoring is likewise bounded but is not replayed from an assessment cache. Treat limits as start-call guards and inspect the local ledger after recovery; API-key operators should also compare it with provider billing.
Cache admission and reuse both check feedback IDs, authorized target paths and key existence against the trusted source evidence. A rejected old cache entry is removed with a private audit record; existing cost and call records remain. Fresh invalid assessments use the same configured attempt limit as other model failures, not an additional retry loop. Each started attempt counts toward the daily session cap. Guardian never repairs a model-invented key by guessing its intended spelling, and repeated invalid output cannot publish edits.
After raw_retention_days, raw comment-body rows are logically deleted from the
active SQLite tables; their body hash and revision metadata remain. SQLite
freelists, WAL files, filesystem snapshots, and backups can retain older bytes,
so this setting is not a secure-erasure guarantee. Protect the state directory
and apply the operator’s storage-retention policy to it and its backups. Do not
publish it.
max_model_calls_per_day is the UTC daily model-call start limit in both
authentication modes. Every assessment and prevention-authoring attempt first
reserves one durable slot atomically. Completed, active, and unknown calls count;
an attempt proved not to have started is cancelled and does not count. The cap
limits Guardian starts, but it is not a ChatGPT-plan guarantee: other Codex use
shares the operator’s plan allowance, and provider limits remain authoritative.
The report-only starter sets the cap to two, enough for one assessment with its
single retry; raise it only from observed workload and allowance data.
The configured cap must at least fit every retry for one assessment. In
observe, prepare, and apply-owned-translations, it requires:
max_model_calls_per_day >= max_attempts
When propose-prevention has a positive draft cap, the cap must leave capacity
for an assessment plus every allowed prevention authoring draft, at every
allowed attempt. Here drafts_per_poll is the smaller of
max_prevention_drafts_per_run and max_prevention_drafts_per_day:
max_model_calls_per_day >= max_attempts * (1 + drafts_per_poll)
This is a configuration-coherence minimum, not reserved capacity for the whole poll. A poll can discover multiple assessments, and prior or earlier calls on the same UTC day can exhaust the cap; remaining work then defers. Each feedback run separately has a value-edit limit, while the prevention-publication cap is shared across the whole poll.
Only API-key mode enables daily_cost_limit_usd and
model_call_reservation_usd. The daily value is the local UTC threshold for
starting another API-billed model attempt, not a provider billing cap. Every
started attempt gets its own conservative cost reservation. A call already in
flight can finish above the threshold, and usage without a reliable price keeps
the reservation as unknown spend. Check provider billing separately,
especially after model-price changes.
For API-key propose-prevention, the cost limit must cover the same worst-case
retry shape:
daily_cost_limit_usd >= model_call_reservation_usd *
max_attempts *
(1 + drafts_per_poll)
For example, one draft, two attempts, and a $5 reservation require a daily API
cost limit of at least $20, plus a call cap of at least four. These are
conservative start reservations, not predictions or provider limits.
A crashed or interrupted translation publication or marked reply is reconciled against the fresh PR head and its durable publication record before any retry. Pending prevention publication is reconciled against the exact target base and branch state. Other work may be assessed again after a crash as described above. Never delete the state database merely to make a pending action disappear.
Stage the user agent only after a clean manual report-only run:
localize guardian install --config "$GUARDIAN_CONFIG"
The generated launchd property list and wrapper contain absolute paths and no
credentials. RunAtLoad plus a conservative StartInterval wakes the wrapper
periodically; persistent state records the start of each poll attempt and uses
top-level schedule.hour (0-23) and schedule.minute (0-59) to decide whether
the once-daily run is due in the machine’s local wall-clock time. The default
is 00:00, preserving earlier behavior. A private process lock in the
config’s state directory prevents a manual run and scheduler wake from starting
overlapping polls;
scheduled lock contention exits successfully while a manual caller receives a
clear already-running error. This provides catch-up after sleep,
logout, or a missed wall-clock time without running the full model workflow
every interval. In the default daily mode, a failed scheduled attempt is not retried on the next 15-minute
wake; use an explicit manual guardian run after diagnosing it. Manual runs
always execute and become that local day’s latest attempt checkpoint.
For responsive open-PR review, opt in in the private configuration:
schedule:
hour: 0
minute: 0
poll_interval_seconds: 900
max_polls_per_day: 96
Each scheduled wake after the configured local start time can then poll GitHub,
at least 900 seconds apart and at most 96 polls per local day. Failed attempts
count too; a crash does not lose the checkpoint. Authentication or provider/model
capacity circuit failures stop subsequent scheduled attempts for that day; diagnose
the cause before an explicit manual retry. These are poll limits, not Codex
session limits: unchanged completed feedback does not start another model session.
The shared limits.max_model_calls_per_day budget still counts every model retry,
and the existing per-run timeouts, bounded model retries, and no-fallback
authentication policy remain unchanged. A run with unfinished feedback can retry
that work, but completed publications retain their existing idempotency checks.
Responsive scheduled polls attempt the closed-PR backlog only once per local day;
later polls concentrate on open PRs and their prevention follow-up. This also means
a failed historical publication waits until the next daily history attempt unless
the operator explicitly runs guardian run without --scheduled after repair.
Manual polls include historical work and count toward the day’s poll checkpoint,
but deliberately bypass scheduling gates. A later successful manual recovery clears
the responsive scheduler’s circuit checkpoint. Omitting poll_interval_seconds
preserves the original once-daily behavior.
install stages the files but does not load the LaunchAgent. The generated
runner is an operator-local artifact beside the external Guardian config, not a
file to commit to the monitored project or this pipeline repository. If staging
fails, installation removes only regular files created by that attempt and
preserves pre-existing logs or artifacts. Inspect the printed property-list,
wrapper, state, and log paths before loading it explicitly. Run
localize guardian status --config "$GUARDIAN_CONFIG" after the first launchd
wake. Re-run doctor after CLI, model, authentication, credential, signing, or
policy changes. If the ChatGPT session expires or is revoked, run
guardian login again before the next scheduled poll.
0700 Guardian directory and
current-user, non-symlink 0600 config and glossary files.observe evidence and prepare audit outcomes were reviewed before enabling
writes; prepare was not mistaken for a retained diff preview.doctor proves
that detached descendants are included in its cleanup scope.GitHub comments are for reviewers, not a machine-data transport. Guardian keeps its structured findings in its private audit state. Public updates must explain what needs attention or what changed, with useful commit links; they must not contain diagnostic JSON or hidden machine payloads.
Keep bot comments action-first and usually one or two sentences: ask for the specific review or decision needed, or say that no action is needed. Routine internal progress belongs in private logs, not another PR comment.
Set GUARDIAN_QUALITY_REPORT_ENABLED=true in the translator environment to
publish one concise, bot-labelled quality summary for a revision with findings.
This summary does not grant Guardian authority to edit anything. In each
Guardian repository policy,
set quality_report_actor: {login: producer-login, id: 12345, type: User} using
the actual producer’s numeric GitHub identity. This existing opt-in enables
internal deterministic quality checks and retains compatibility with older
reports. It is separate from the reviewer whitelist: ordinary comments by that
actor confer no review authority.
The initial scope is unexpected source-identical values and disallowed control characters in changed entries. Guardian derives findings from exact base/head checkouts using the trusted brand/ignore policy, rather than relying on a public comment. Findings are bound to the repository, PR, commits, target path, locale, and source/target values and are revalidated before publication. An unreproduced finding is recorded as rejected with insufficient evidence and excluded from model input and recurrence authority. Other verified findings and trusted review feedback in the same poll can still proceed; an invalid-only batch makes no model call and does not read or populate the assessment cache. Source-echo flags do not prove shared-language wording is wrong; the assessment must still distinguish a defect from legitimate identical wording. Placeholder, semantic, glossary and model-failure narratives do not independently authorize edits; those still need trusted review feedback. No arbitrary check-status or PR-body text is consumed as authority.
Internal per-key events let edit limits retain unfinished work. Public dispositions are consolidated in the existing PR summary. Only a durably recorded Guardian commit can carry unresolved evidence forward; an external head change requires fresh evidence. Already-published corrections may supply historical prevention evidence, but cannot authorize another edit. Evidence limits fail explicitly instead of silently dropping findings.
To publish a human-readable check summary for an existing PR without model calls, use an exact local head and the trusted operator configuration. Guardian does not need this comment to perform its internal checks:
python -m localize.guardian.quality_report_publication \
--repository owner/project --pull-number 123 --expected-head FULL_HEAD_SHA \
--repo-root /path/to/checkout --input-folder /path/to/checkout/l10n \
--config /path/to/trusted/config.yaml
The producer rejects modified report target/source files and source differences from the current PR base. Other pending translation batches remain untouched. It posts only the summary and prints separate internal finding/report counts and public comment counts. Rerunning with the same findings at the same revision does not duplicate the comment. An unchanged English value is a candidate for review, not proof of a mistranslation; product names and shared-language terms may correctly remain unchanged.