Reviewer grant trust file
Independent review and authenticated directives are authorised by an lfdg2 grant. The grant is
signed with an Ed25519 private key that you hold outside every agent session. Every
LumenFlow process verifies it against a public trust file, so no agent process holds a secret that
could mint a grant.
1. Generate a keypair outside any agent session
Section titled “1. Generate a keypair outside any agent session”Generate an Ed25519 keypair in a shell that no agent controls (another OS user or another
machine is best). Keep the private key file readable only by you and never place it in a
repository, an environment variable, shared memory or a transcript. Derive the raw 32-byte public
key as hex and its kid, the lowercase hex SHA-256 of those raw bytes. Record the kid somewhere
independent, such as your own notes or a second machine.
2. Install the trust file at the system path
Section titled “2. Install the trust file at the system path”The file lists public keys only:
Install it as root or Administrator, owned by root or Administrators and not writable by group or others:
| Platform | System path |
|---|---|
| Linux | <system config directory>/grant-trust.json |
| macOS | <system config directory>/grant-trust.json |
| Windows | C:\ProgramData\LumenFlow\grant-trust.json |
Every directory above the file up to the root must also be owned by root or Administrators, not
writable by group or others, and not a symlink. No environment variable, workspace config or repository path
can supply keys to the enforcing system anchor. A per-user trust file is
diagnostic only: it reports trust_level: user-writable and never satisfies a required
review. A system file that exists but is unsafe or malformed fails closed and is never replaced by
the per-user file.
3. Issue an lfdg2 grant
Section titled “3. Issue an lfdg2 grant”From your own shell, call issueDirectiveIssuerGrant (the
@hellmai/lumenflow-cli/directive-grant-authority export) with privateKeyFile pointing at your
private key, plus the reviewer role session, scope key and exactly one WU. The TTL defaults to 15
minutes (1 to 60). The result is an lfdg2.<payload>.<signature> token, single use.
4. Record the review
Section titled “4. Record the review”The reviewer records the verdict with the grant:
No signing key is needed in this shell: verification reads only the public trust file.
Authority separation and limits
Section titled “Authority separation and limits”A grant is signed for exactly one purpose (reviewer or directive) and each boundary refuses the other. A trust file that repeats a kid, or lists no keys, is refused as malformed, so to revoke a key edit its existing entry (set revoked_at) instead of appending a second one. A grant may span at most 60 minutes between issued_at and expires_at. Because retiring a key with not_after does not stop a leaked key from signing new short grants, revoke any key that may have leaked.
Rotation and revocation
Section titled “Rotation and revocation”- Rotate: add the new key to the trust file and set
not_afteron the old key. A grant is judged by its ownissued_at, so reviews recorded before the rotation keep verifying. - Revoke: set
revoked_aton a compromised key. Every grant of that key is then refused, even recorded evidence, and affected work units need a fresh review under a new key. - The file is re-read on every verification, so both take effect at once.
Refusals you may see
Section titled “Refusals you may see”| Code | Meaning |
|---|---|
grant_legacy_hmac_refused | An lfdg1 HMAC grant. Issue an lfdg2 grant instead. |
grant_tampered | The signature does not verify. |
grant_expired | The grant’s own expiry has passed. |
grant_missing_trust_anchor | No safe system trust file (absent, unsafe, or only a user file). |
grant_untrusted_issuer | The key is unknown, outside its validity window, or revoked. |
grant_wrong_purpose | The grant was signed for the other purpose (reviewer versus directive). |
grant_malformed | The token is not the one canonical spelling of a valid grant. |
grant_replayed | The grant was already consumed. |