Appearance
Credential Model — Itachi-Direct + Vaultwarden (CT103)
Naming note 2026-06-11: "Bitwarden" throughout this doc reads as Vaultwarden (self-hosted, CT103, 192.168.1.250) per the 2026-06-10 supersede block at the end of this file. project: hinata-infrastructurestatus: livingowner: michael + itachicreated: 2026-05-26
Decision (live 2026-05-26)
Itachi-direct stays the default through the home-lab bring-up. Bitwarden adoption deferred to the first month after Pi + Z2 are operational, then adopted as a SPLIT model — not a replacement.
Original deferral (2026-05-24): "until self-hosting equipment is delivered." That trigger fires this week — Z2 arrived 2026-05-26, Pi arrives 2026-05-27. Re-evaluation date for full Bitwarden activation: 2026-06-15 (3 weeks of operational data from the new hosts).
Why a split, not a replacement
Itachi-direct has a property Bitwarden doesn't: vault-native + offline-readable + no daemon dependency. Bitwarden has a property Itachi doesn't: scale + sync-to-VMs + per-credential audit trail. The right move is to route by risk profile.
Routing rules
Credential classStorageWhy
Root credentials, recovery keys, legal/family docsItachi-directLow rotation, high trust, single-reader-on-Mac. Vault offers offline + iCloud sync without a sync daemon. Per-VM users, SSH host keys for home-lab boxesItachi-direct (boot-time) → Bitwarden (runtime)Mac script reads Itachi to deploy at provision time; the VM itself runs Bitwarden CLI for its own runtime needs. Per-service API keys (Monzo, TrueLayer, Anthropic, Telegram bot)Itachi-direct today; Bitwarden post-2026-06-15Rotation cadence is medium; volume is growing. Ephemeral lab creds (Postgres roles, Ollama dev keys, n8n webhooks)Bitwarden from day one (post-2026-06-15 activation)High churn, high count. Putting these in the vault pollutes git history. Cloudflare API token, Tailscale auth-keyItachi-directSingle-rotation per year; vault-native is fine. Database passwords (jimmy-vps Postgres, Z2 Proxmox root)Bitwarden post-activationPer-host rotation needs; multiple consumers; Bitwarden audit trail wins here.
Trade-off table
PropertyItachi-directBitwarden hostedVaultwarden (self-hosted on Pi)
Friction per accessLow (read file)Medium (CLI + unlock)Medium (CLI + unlock) Sync across devicesiCloud (free, slow)Native, sub-secondLAN-only (until Tailscale extends it) Sync to VMsManual (scp / git)Native via CLINative via CLI Audit trailGit log (coarse)Per-credential access logPer-credential access log Vault portabilityMarkdown — perfectJSON exportJSON export Monthly cost£0£0 (free tier)£0 (hosted on Pi) Offline readYes (iCloud cached)No (without local cache)No (if Pi off) Daemon dependencyNoneBitwarden CLI + browser extVaultwarden process on Pi
Vaultwarden rejected for now — adds a host-dependency layer when Pi is already carrying cron orchestration; one extra responsibility per host is the threshold.
Bitwarden migration checklist (activates 2026-06-15)
(blocker) Provision Bitwarden account + install CLI on Mac (1hr).
Migrate
ANTHROPIC_API_KEYfirst as proof — out of any plistEnvironmentVariablesblock, into Bitwarden, daemon reads frombw get itemat start. Validate before moving anything else.Migrate
TELEGRAM_BOT_TOKENnext — same pattern.Audit every LaunchAgent plist for plaintext credentials in
EnvironmentVariablesblocks. Mechanical scan for token-shape strings, no credential values logged.Per-credential migration thereafter — never big-bang. One per session, validate consumer, then move on.
Itachi
*.jsonfiles for migrated credentials get a frontmatter flagmigrated: bitwarden YYYY-MM-DDand the credential field is replaced withmigrated → bw://item-id. The Itachi file stays for git audit history.
Pre-activation hardening (do before Pi arrives)
.gitignorealready excludes*.token,*.key,tokens_*.json. Re-verify against new file shapes (Z2 BIOS export, Pi user creds).Add a pre-commit hook to the vault that refuses to commit files containing bearer-token-shape strings.
feedback_never_print_credentialsis the operational rule — re-affirm at top of each Pi/Z2 SSH session.
Stop conditions
* Do NOT print credential VALUES at any point — names, lengths, locations only.
* Do NOT rotate existing credentials during migration.
* Do NOT activate Bitwarden before 2026-06-15 without re-reading this doc.
Re-evaluation triggers
* 2026-06-15 (Bitwarden activation review)
* Credential count in Itachi exceeds 30 (threshold for forced reconsideration)
* Any LaunchAgent plist needs a credential rotation more than once per quarter
Amendment (2026-06-10, Michael ruling — 800124)
Hosted Bitwarden is deprecated. The store is self-hosted Vaultwarden at 192.168.1.250 (CT103 on Z2) — same bw CLI protocol, same split-model routing rules: every "Bitwarden" above now reads "Vaultwarden". Activation is live as of 2026-06-10, ahead of the 2026-06-15 review (Michael migrating credentials in; the new Telegram bot token is the first canonical entry). Known cleanup: duplicate anthropic_api_key entries observed during migration — dedupe owned by Michael + Itachi; never auto-rotate, never print values. 192.168.1.250 is a LAN address — Tailscale-bind hardening belongs to the binds task (800127), not unilateral change.
◆ hinata · projects/hinata-infrastructure/credential-model.html · phase-19 conversion
Canonical paths (2026-06-14, Michael ruling — credential paths uniform is itachi plan)
Itachi owns auth strategisation. The flat-file/Vaultwarden split below is the law; deviations are violations, not patterns.
Path law
| Class | Storage | Canonical location | Why |
|---|---|---|---|
| Secret-class (API tokens, OAuth client_id/client_secret, bot tokens, DB passwords) | Vaultwarden | item name e.g. hinata_[commander]_[service]_token | Audit trail, no plaintext on disk, cross-container reachable via bw get |
| OAuth refresh-token cache (polling agents that re-mint access tokens) | Filesystem flat-file | /mnt/data/hinata/data/[commander]/tokens_[service].json on Z2 | Pollers must read locally without bw-unlock loop; container bind reads at runtime |
| Mac-bound OAuth callback caches (browser localhost flow) | Filesystem flat-file (Mac) | ~/Sandpit/hinata-sandpit/data/[commander]/tokens_[service].json then synced to Z2 canonical path | Browser callback only resolves to Mac localhost; cache is intermediate, Z2 path is source-of-truth post-sync |
Deprecated paths (2026-06-14 — DO NOT recreate)
/opt/jimmy-brain-ops/secrets/— entire folder evicted; never write secrets under/opt/again. Scripts must read from/mnt/data/hinata/data/[commander]/only./mnt/data/itachi-credentials/— evicted; canonical path collapsed to/mnt/data/hinata/data/[commander]/.- Any per-script
secrets/subdirectory under a script's install path. ~/.config/[service]/credentials*for hinata-owned services on Z2 — must move into the canonical/mnt/data/hinata/data/tree.
Naming law
- Vaultwarden item names:
hinata_[commander]_[service]_[purpose]. Examples:hinata_bulma_trading_212_token,hinata_studio_access.- Michael owns naming. Agents NEVER
bw create/bw edit(per feedback_no-auto-vaultwarden-writes). Agents propose names; Michael writes.
- Michael owns naming. Agents NEVER
- Flat-file names:
tokens_[service].json(refresh-token cache) or[service]_credentials.json(Mac-bound OAuth callback intermediate only). - One token-class per file. No mixed structures.
Read pattern
| Consumer | How it reads |
|---|---|
| Mac scripts (any) | read-credentials.sh → SSH to Z2 → bw get item [name] |
| Z2 container poller | local file at /mnt/data/hinata/data/[commander]/tokens_[service].json (bind-mounted) |
| Z2 container at startup (non-poller) | bw get item [name] via CT103 SSH/pct exec |
| CT106 (telegram bot) | /etc/hinata/telegram.env env file backed by Vaultwarden |
Migration of historic loose credentials
Any flat-file matching *credentials*.json / *token*.json / .env* outside the canonical paths above is non-compliant. Migration triage:
- KEEP — file lives at canonical path AND is OAuth-refresh-cache class (correct usage).
- MIGRATE — file is at non-canonical path; relocate to canonical path; update consumer.
- VAULTWARDEN — file holds secret-class material (client_id/client_secret, raw API tokens that aren't refresh-rotated); Michael moves to Vaultwarden manually, file deleted post-confirm.
- DELETE — vestigial duplicate or pre-collapse remnant.
Audit: 2026-06-14 audit.
Enforcement (Itachi standing rules)
- New script written by any agent that introduces a credential path MUST land under
/mnt/data/hinata/data/[commander]/on Z2 (or the Mac-bound equivalent for callback paths only). Reviewers reject otherwise. - Any reference to
/opt/jimmy-brain-ops/secrets/or/mnt/data/itachi-credentials/in active code is a defect. Tombstone and replace. - Credentials in source files (
_middleware.js,.env*, config) must not be modified by any agent without explicit Michael instruction — see feedback_no-credential-in-code-modification. - Vault commits that print credential values fail review on sight per feedback_no-credential-print.
Ownership (2026-06-14 ruling)
Michael ruling, verbatim:
"jimmy why would jimmy have ownership of any secrets or tokens in cache ? is that necessary ? is itachi not supposed to own all credential auth flows why is json for credentials anywhere else?"
Itachi is the sole owner of every credential surface. This is total ownership across the federation — no other captain, commander, or colonel holds credential authority in their domain.
Surfaces Itachi owns
| Surface | What Itachi owns |
|---|---|
| Vaultwarden items | Naming proposals (Michael writes), rotation cadence, retirement, audit |
| Flat-file token caches | Path, filename, format schema, refresh policy, rotation triggers |
| OAuth callback flows | Callback host, redirect URI, intermediate cache path, sync-to-Z2 protocol |
| In-container env files | EnvironmentFile path, key naming, backing source (Vaultwarden CLI vs flat-file) |
| Source-file credential refs | Authorisation of any change per feedback_no-credential-in-code-modification |
| Rotation policy | Quarterly cadence (per Itachi credential-rotation-brief), trigger thresholds |
| Auth-flow design | OAuth client architecture, scopes, token TTL, refresh strategy |
Per-consumer-commander paths are Itachi-OWNED-BY-POLICY
The canonical path /mnt/data/hinata/data/[commander]/tokens_[service].json lives under a commander-named directory for read-locality only — the bind-mount lets that commander's container read locally without an unlock loop. The consumer reads what Itachi sanctions. The path, filename, format, and rotation are Itachi's. The consumer-commander does not author, rename, or restructure the file.
Example: /mnt/data/hinata/data/bulma/tokens_monzo.json is Itachi-owned. Bulma's poll-monzo.py reads it. Bulma does not declare schema, does not author rotation cadence, does not change filename. If Bulma's needs require a schema change, Bulma raises it to Itachi.
Forbidden — other agents declaring credential ownership
No captain or commander may declare a credential surface in their context file. If a federation context contains language like "X owns the secrets for service Y" outside Itachi's context, it is a violation — see feedback_itachi-owns-all-credential-paths. Such declarations get tombstoned to "credentials via Itachi" with a wiki-link here.
Path bans (re-affirmed)
/opt/jimmy-brain-ops/secrets/— forbidden by name. Will not be re-created under any circumstance. This path was never Itachi-named — its existence was a domain-overreach by Jimmy and is permanently evicted./mnt/data/itachi-credentials/— deprecated despite being Itachi-named. The structure was non-canonical (single flat directory rather than per-consumer-commander subtree). Collapsed into/mnt/data/hinata/data/[commander]/on 2026-06-14. Will not be re-created./opt/itachi/credentials/(CT102, CT103) — transitional during Vaultwarden backfill; once empty, the directory itself is retired, not re-stocked.