credential-daemon
AGENTS.md10 starsChanged 5 days agoApache-2.0View on GitHub
Instructions for AI coding agents working in this repository. Adapting for your agent. This file is the agent-neutral source of truth for the always-on rules; longer, task-scoped guidance lives in .agents/ (see below). Agent-specific entrypoints (CLAUDE.md, .cursorrules, .github/copilot-instructions.md, etc.) are gitignored — point yours at this file locally. For agents that read a fixed filename, symlink it: ln -s AGENTS.md CLAUDE.md. Keep any agent-specific rules or skills local until they can be extracted into an agent-neutral, committable form. .agents/ holds…
- Installs packages
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,439 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository2 other files it gives its agents.
- audit-specsSkill
- security-reviewSkill
The file
Show its rules and text
We split this AGENTS.md into the rules it gives an agent
21 rules. About 0 are common, 8 are distinctive, and 13 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈8
Distinctive · estimate
This author's own choices. Worth a look.
13
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Distinctive: line 26
Not every skill a maintainer runs is in there — ones that automate a personal workflow or need account-specific access stay local and …
- Distinctive: line 38
Always run fmt, clippy, and test before committing.
- Very specific: line 66
Read the region column, not lines: it counts match arms and ?
- Very specific: line 70
Every output form lands under target/, so nothing needs its own .gitignore entry.
- Distinctive: line 92
No comments unless explaining a non-obvious WHY (hidden constraint, workaround, surprising behavior)
- Very specific: line 93
No TODO/FIXME in code — track in private/TODO.md instead
- Very specific: line 95
Use thiserror derives for new error variants
- Very specific: line 98
Test modules: #[cfg(test)] mod tests { ...
- Very specific: line 112
Do not give daemon-only state a TOML file: it reads as an invitation to hand-edit, and for state like the enrolled-key registry a hand-edit …
- Distinctive: line 164
Keep the subject line under 72 characters.
- Distinctive: line 172
Update the spec (requirements and/or design) in the same commit as the code change.
- Distinctive: line 173
Write a commit message that explains why the spec changed (not just what).
- Very specific: line 174
If the spec's status is complete, revert it to accepted until re-verified.
- Distinctive: line 180
If unsure whether a spec applies, err on the side of checking — reading a spec's requirements takes less time than debugging a silent …
- Very specific: line 182
When writing or reviewing a spec or design, also check it for platform one-way doors — choices that would foreclose a future platform or …
- Very specific: line 186
Do not commit without running cargo fmt
- Very specific: line 187
Do not suppress clippy warnings with #[allow(...)] without justification
- Distinctive: line 188
Do not add dependencies without checking they're necessary and maintained
- Very specific: line 189
Do not use unsafe without a safety comment and prior discussion
- Very specific: line 190
Do not write to stdout in library code (only in main.rs / command handlers)
- Very specific: line 191
Do not hardcode paths — use config::platform for OS-specific directories
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Agent Guidelines
Instructions for AI coding agents working in this repository.
Adapting for your agent. This file is the agent-neutral source of truth for the always-on rules; longer, task-scoped guidance lives in
.agents/(see below). Agent-specific entrypoints (CLAUDE.md,.cursorrules,.github/copilot-instructions.md, etc.) are gitignored — point yours at this file locally. For agents that read a fixed filename, symlink it:ln -s AGENTS.md CLAUDE.md. Keep any agent-specific rules or skills local until they can be extracted into an agent-neutral, committable form.
Further Guidance
.agents/ holds guidance too long or too situational for this file:
.agents/rules/— standing rules that apply to every change.minimalism.mdis the decision ladder to descend before writing any code;spec-voice.mdis how to write a spec;platform-one-way-doors.mdis what to look for in a spec or design that would be expensive to reverse if another platform is supported later..agents/skills/— task-scoped procedures invoked on demand:security-review(pre-PR diff review and whole-system audit) andaudit-specs(requirements-to-code drift). See.agents/README.mdfor wiring them into your harness.
Not every skill a maintainer runs is in there — ones that automate a personal workflow or need account-specific access stay local and uncommitted.
Build Commands
cargo fmt # format code (required before commit)
cargo clippy -- -D warnings # lint (must pass with zero warnings)
cargo test # run all tests (must pass)
cargo build # verify compilationAlways run fmt, clippy, and test before committing. The pre-commit hook enforces fmt and clippy; tests run in CI.
Coverage
Coverage needs two separate pieces, which is why it is not configured in one place:
| Piece | What it is | Comes from |
llvm-tools-preview | rustup component (the profdata tooling) | rust-toolchain.toml — automatic |
cargo-llvm-cov | a standalone cargo subcommand binary | cargo install — one-time, per machine |
It is not a Cargo dependency and never appears in Cargo.toml. There is no rustup
component for it, so the toolchain file cannot supply it.
cargo install cargo-llvm-cov --locked # one-time setup
cargo llvm-cov --summary-only # per-file table, printed to stdout
cargo llvm-cov --html --open # annotated source; writes target/llvm-cov/html/To render several views without re-running the suite, instrument once then report:
cargo llvm-cov --no-report # run tests, keep the profile data
cargo llvm-cov report --summary-only # then as many report forms as you like
cargo llvm-cov report --html --openRead the region column, not lines: it counts match arms and ? early-returns
separately, which is where the classification logic lives. Coverage is not a commit
gate — CI runs it on one row and uploads target/lcov.info as an artifact.
Every output form lands under target/, so nothing needs its own .gitignore entry.
--lcov is the one form with no default location, so it takes an explicit
--output-path target/lcov.info.
Two things coverage will not tell you. Instrumented builds use their own RUSTFLAGS
and a separate target/llvm-cov-target/ build dir, so they do not share artifacts with
cargo build — alternating between the two rebuilds each time, which is expected, not
a broken cache. And tracing does not evaluate a log macro's field expressions unless
a subscriber is installed, so audit-record fields read as covered while nothing has
checked them. No test currently installs one, so no audit record's contents are asserted
anywhere; a test that needs to check emitted fields has to stand up its own subscriber.
Toolchain
Pinned in rust-toolchain.toml. Do not change the channel without discussion. All formatting decisions come from this version's rustfmt — do not override with local config.
components includes llvm-tools-preview so cargo llvm-cov works after a plain
checkout. Removing it breaks coverage for everyone, including CI, which has no
install step of its own.
Code Style
- No comments unless explaining a non-obvious WHY (hidden constraint, workaround, surprising behavior)
- No TODO/FIXME in code — track in
private/TODO.mdinstead - Error types: use
DaemonErrorvariants via theerror.rsenum. Noanyhow, nounwrap()in library code - Use
thiserrorderives for new error variants - Secrets/keys: wrap in types that implement
Zeroize + Drop. Never log secret values. - Platform-specific code: gate with
#[cfg(target_os = "...")], keep in platform-specific modules (e.g.,storage/macos.rs) - Test modules:
#[cfg(test)] mod tests { ... }at the bottom of each file. Useproptestfor output-format and serialization properties.
Persisted Formats
A file's format says who writes it. Pick by writer, not by taste:
| Writer | Format | Examples |
| A person, by hand or through the CLI | TOML, mutated with toml_edit so comments survive | config.toml, credentials.toml |
| The daemon alone | JSON plaintext sealed with EncryptionService::seal_to_file, named *.enc | sso_token.enc, iam_user.enc |
| A key | a SecureStorage slot, never a file the daemon formats | master key |
| The daemon alone, and must not be restorable | a SecureStorage slot under data-protection-keychain; otherwise a sealed *.enc outside every caller root, owned by the service account | enrolled-key registry, integrity record |
| The client alone | JSON plaintext, 0600, in ~/.credsd/ — never the daemon's data dir | presence-key.json |
Do not give daemon-only state a TOML file: it reads as an invitation to hand-edit, and for
state like the enrolled-key registry a hand-edit is the attack. Do not add a plaintext
.json for daemon state either; if it is worth persisting, seal it — being public is not a
reason to skip sealing. ra_public.json (a Roles Anywhere certificate chain) predates this
rule and is the one existing exception.
The client has no master key, so it cannot seal; what it persists must be safe unsealed, like a
key wrapped by the Secure Enclave. Keep it in ~/.credsd/ even when a user-scoped daemon's data
dir is also under $HOME: one writer per directory.
Project Structure
Four crates, two binaries, and the crate directory names do not match the binaries:
crates/credsd builds creds (the client) and crates/credsd-daemon builds credsd
(the daemon).
crates/
├── credsd-core/src/ shared internals; no server
│ ├── error.rs DaemonError enum
│ ├── config/ config + credential files, platform paths
│ ├── storage/ SecureStorage trait + platform backends
│ ├── providers/ CredentialProvider trait + implementations
│ ├── rpc/ JSON-RPC envelope, codec, method surface, the client-side
│ │ UDS call (`rpc/uds.rs`)
│ ├── encryption.rs AES-256-GCM envelope encryption
│ ├── credentials.rs Credential data model
│ ├── credential_resolve.rs Credential fetch over the daemon socket
│ ├── credential_env.rs Credential variable naming + env-var formatting
│ ├── projection.rs How a credential reaches its consumer
│ ├── presence.rs Presence challenge + enrolled-key types
│ ├── bootstrap.rs Interactive credential setup
│ └── get.rs Output formatting (credential_process, shell, etc.)
├── credsd-daemon/src/ the `credsd` binary
│ ├── main.rs CLI (clap) + subcommand dispatch
│ ├── server/ UDS accept, caller assessment, dispatch, presence gating
│ ├── credential_store.rs In-memory cache + background refresh
│ ├── install.rs launchd / systemd service install
│ └── hardening.rs Process hardening applied before any key is loaded
├── credsd/src/ the `creds` binary: the unprivileged client CLI
└── credsd-client/src/ the public Rust client library for the socket protocolPer-file detail goes stale faster than it earns its keep; docs/specs/ and docs/design/
are the authority for behavior, and ARCHITECTURE.md for how the crates fit together.
Commit Style
Conventional commits: type: short description
Types: feat, fix, refactor, test, docs, style, chore, ci
Keep the subject line under 72 characters. Body is optional — use it for non-obvious reasoning.
Spec Coherence
When modifying code that is covered by a spec (docs/specs/*/), check whether the behavioral change contradicts any MUST/SHALL criterion in the spec's requirements.md. If it does, stop and surface the conflict to the user before proceeding. Do not unilaterally modify spec requirements to match your implementation — spec changes require explicit user approval.
Once the user has approved the direction:
- Update the spec (requirements and/or design) in the same commit as the code change.
- Write a commit message that explains why the spec changed (not just what).
- If the spec's status is
complete, revert it toaccepteduntil re-verified.
The only exception to requiring approval is correcting a spec that is provably inconsistent with itself (internal contradiction) or with an upstream constraint the spec failed to account for. Even then, flag the correction for review in the commit message.
To determine if a spec covers your change: check if the files you modified appear in the spec's design.md "File changes" table, or if the behavior you're altering is described in the spec's acceptance criteria.
If unsure whether a spec applies, err on the side of checking — reading a spec's requirements takes less time than debugging a silent design drift.
When writing or reviewing a spec or design, also check it for platform one-way doors — choices that would foreclose a future platform or force a rewrite rather than just add per-platform work. See .agents/rules/platform-one-way-doors.md.
What Not To Do
- Do not commit without running
cargo fmt - Do not suppress clippy warnings with
#[allow(...)]without justification - Do not add dependencies without checking they're necessary and maintained
- Do not use
unsafewithout a safety comment and prior discussion - Do not write to stdout in library code (only in
main.rs/ command handlers) - Do not hardcode paths — use
config::platformfor OS-specific directories
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

