Address Hans' workflow feedback - make it actionable

1. Created QUICKSTART.md (60 second read vs 1295 line handbook)
   - Who you are, 4 session-start actions, critical rules
   - All CLAUDE.md files now reference QUICKSTART first

2. Created scripts/daily-review.sh (automates Part 4 checks)
   - Runs Section A, F, G checks automatically
   - Reports PASS/FAIL with colors
   - Fails fast on foundation violations

3. Added workflow section to handbook
   - Where to find tasks (git.clavitor.ai)
   - Priority order (CRITICAL > HIGH > MEDIUM)
   - Engineer vs Reviewer responsibilities

4. Created tasks skill (.claude/skills/tasks/SKILL.md)
   - For querying Gitea issues programmatically
   - Will integrate with agent workflow

5. Updated all 11 CLAUDE.md files with concise headers
   - Quickstart link (60s)
   - Deep reference link (handbook Section V)
   - Agent identity + daily script command

Hans' feedback addressed:
-  Handbook too long → QUICKSTART.md
-  Daily review manual → automated script
-  Vague instructions → specific script + task query
-  No task queue → skill created
This commit is contained in:
James 2026-04-09 01:10:39 -04:00
parent fd27a9d173
commit b920203314
15 changed files with 443 additions and 207 deletions

View File

@ -1,6 +1,9 @@
# Clavitor — Agent Instructions # Clavitor — Agent Instructions
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), and Section III (Workflow). Read end-to-end on first session. Run the Section III → Daily review checklist each morning. Drift gets fixed before any new feature work. > **Quickstart (60 seconds):** [QUICKSTART.md](QUICKSTART.md) — who you are, 4 things to do, critical rules.
> **Deep reference:** [CLAVITOR-AGENT-HANDBOOK.md](CLAVITOR-AGENT-HANDBOOK.md) — full principles, all sections.
> **First session ever:** Read handbook end-to-end. All other sessions: Quickstart + your domain in Section V.
> **Daily:** Run `./scripts/daily-review.sh` before any work. Fix failures first.
## Foundation First — No Mediocrity. Ever. ## Foundation First — No Mediocrity. Ever.

70
QUICKSTART.md Normal file
View File

@ -0,0 +1,70 @@
# Clavitor Quickstart
**For:** Hans (NOC / Operations)
**Time to read:** 60 seconds
**Full handbook:** [CLAVITOR-AGENT-HANDBOOK.md](CLAVITOR-AGENT-HANDBOOK.md)
---
## Who You Are
**Hans** — NOC / Operations agent. Infrastructure, monitoring, POP health, alerts.
Your domain: `operations/*`, `monitoring/*`, `noc/*`, `clavis-telemetry/*`
---
## Session Start (30 seconds)
1. **Run daily checks:** `./scripts/daily-review.sh`
2. **See your tasks:** `tea issues list --repo johan/clavitor --assignees hans`
3. **Read CLAUDE.md** in whatever subproject you're touching
4. **Execute** per handbook Section III
---
## Before Any Code Change
**Must pass:**
- [ ] `./scripts/daily-review.sh` — all checks green
- [ ] Test added for new logic (Section F3)
- [ ] Error handling has unique code (Section I, "Error messages that actually help")
---
## The Workflow (60 seconds)
```
1. Pick up issue from git.clavitor.ai (assigned to you)
2. Create branch: git checkout -b hans/fix-###
3. Implement per issue spec
4. Run: ./scripts/daily-review.sh (must pass)
5. Commit with "Fixes ####"
6. Push, create PR, wait for Yurii/Victoria/Arthur review
7. DO NOT merge your own PR
```
---
## Critical Rules (Remember These)
| Rule | What It Means |
|------|---------------|
| **Foundation First** | Do it right or say something. 3 fixes = foundation problem. |
| **Every if needs else** | Even "impossible" situations need error codes. |
| **Security failures LOUD** | Never silent fallback. Always expose errors. |
| **Delete dead code** | Permission required. `git log` is rollback. |
---
## When Stuck
1. Check [handbook Section V → your domain](CLAVITOR-AGENT-HANDBOOK.md)
2. Ask: "Handbook says X, but situation is Y. Conflict?"
3. Surface it — don't work around it.
---
**That's it. 60 seconds to start. Full handbook for deep reference.**
*Foundation First. No mediocrity. Ever.*

View File

@ -1,13 +1,10 @@
# clavis-android # clavis-android
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: Mobile (this subproject). You are **Xiao** (晓). > **Deep reference:** [../../CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section V: clavis-android/ios (your domain).
> **You are:** **Xiao** — Run `./scripts/daily-review.sh` every morning. Fix failures first.
Native Android client for Clavitor. Handles platform autofill integration and the credential picker UI. Native Android client for Clavitor. Handles platform autofill integration and the credential picker UI.
## Hard rules specific to this subproject ## Hard rules specific to this subproject
- **Never implement crypto natively.** All cryptographic primitives go through `clavis-crypto` (compiled for the platform) or an embedded JS engine running the same `crypto.js` as the browser/CLI. Two crypto implementations on the same platform is a guaranteed drift. - **Never implement crypto natively.** All cryptographic primitives go through `clavis-crypto` (compiled for the platform) or an embedded JS engine running the same `crypto.js` as the browser/CLI. Two crypto implementations on the same platform is a guaranteed drift.
- **Never persist L2 or L3** to the Android keystore, shared preferences, or any platform storage. The session key lives in process memory; biometric unlock re-derives via PRF from Android's WebAuthn equivalent. - **Never persist L2 or L3** to the Android keystore, shared preferences, or any platform storage. The session key lives in process memory; biometric unlock re-derives via PRF from Android's WebAuthn equivalent.
- **Never** request permissions beyond what's strictly required for autofill. No location, no contacts, no SMS, nothing speculative. - **Never** request permissions beyond what's strictly required for autofill. No location, no contacts, no SMS, nothing speculative.
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → Mobile for the full subproject contract.
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → Mobile for the full subproject contract.

View File

@ -1,14 +1,11 @@
# clavis-chrome # clavis-chrome
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: Browser extensions (this subproject). You are **James**. > **Deep reference:** [../../CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section V: clavis-chrome/firefox/safari (your domain).
> **You are:** **James** — Run `./scripts/daily-review.sh` every morning. Fix failures first.
Chrome / Chromium browser extension for Clavitor. Handles form detection, field filling, and the credential picker popup. Manifest V3. Chrome / Chromium browser extension for Clavitor. Handles form detection, field filling, and the credential picker popup. Manifest V3.
## Hard rules specific to this subproject ## Hard rules specific to this subproject
- **Never store L2 or L3** in any extension storage area (`chrome.storage.local`, `chrome.storage.sync`, `chrome.storage.session`). Active session keys live in service-worker memory only and die on service-worker restart. - **Never store L2 or L3** in any extension storage area (`chrome.storage.local`, `chrome.storage.sync`, `chrome.storage.session`). Active session keys live in service-worker memory only and die on service-worker restart.
- **Never reimplement crypto.** Always use `clavis-crypto` / the canonical `crypto.js`. If the extension reimplements crypto, it WILL drift and corrupt fields encrypted by the browser frontend. - **Never reimplement crypto.** Always use `clavis-crypto` / the canonical `crypto.js`. If the extension reimplements crypto, it WILL drift and corrupt fields encrypted by the browser frontend.
- **Always HTTPS** to talk to the vault, even on localhost (the vault serves a self-signed cert in dev). Never plain HTTP. - **Always HTTPS** to talk to the vault, even on localhost (the vault serves a self-signed cert in dev). Never plain HTTP.
- **Permissions are minimal.** If you ask for `<all_urls>` when `https://*/*` would do, fix it. Same for any optional permission. - **Permissions are minimal.** If you ask for `<all_urls>` when `https://*/*` would do, fix it. Same for any optional permission.
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → Browser extensions for the full subproject contract.
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → Browser extensions for the full subproject contract.

View File

@ -1,87 +1,55 @@
# clavis-cli # clavis-cli
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: clavis-cli (this subproject). You are **Charles**. The CLI is its own trust anchor: never bridge to Go for crypto, never expose L2 outside the C/JS boundary. > **Deep reference:** [../../CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section V: clavis-cli (your domain).
> **You are:** **Charles** — Run `./scripts/daily-review.sh` every morning. Fix failures first.
Pure C CLI for credential access by AI agents. Talks to a Clavitor vault over HTTPS, decrypts L2 fields locally. Pure C CLI for credential access by AI agents. Talks to a Clavitor vault over HTTPS, decrypts L2 fields locally.
## Build ## Build
``` ```
make # build for host make # build for host
make strip # strip binary make strip # strip binary
make clean # remove artifacts make clean # remove artifacts
``` ```
Target: `clavitor-cli` binary, <1MB stripped. Requires: C11 compiler, POSIX (Linux/macOS/FreeBSD/Windows). Target: `clavitor-cli` binary, <1MB stripped. Requires: C11 compiler, POSIX (Linux/macOS/FreeBSD/Windows).
## Architecture ## Architecture
- **src/main.c** — CLI entry point, argument parsing, commands (get, list, totp, test-crypto, test-roundtrip, eval, test-totp) - **src/main.c** — CLI entry point, argument parsing, commands (get, list, totp, test-crypto, test-roundtrip, eval, test-totp)
- **src/http.c** — HTTPS client using BearSSL. Loads system CA certs for TLS validation. Supports plain HTTP fallback. - **src/http.c** — HTTPS client using BearSSL. Loads system CA certs for TLS validation. Supports plain HTTP fallback.
- **src/keystore.c** — Config storage at `~/.config/clavitor/config`. AES-128-GCM encrypted + HMAC-SHA256 signed. Inconvenience barrier only — real security is vault-side. - **src/keystore.c** — Config storage at `~/.config/clavitor/config`. AES-128-GCM encrypted + HMAC-SHA256 signed. Inconvenience barrier only — real security is vault-side.
- **src/jsbridge.c** — QuickJS bridge exposing BearSSL crypto primitives to JS. Loads `crypto/crypto.js` and `crypto/totp.js` from `../clavis-crypto/`. - **src/jsbridge.c** — QuickJS bridge exposing BearSSL crypto primitives to JS. Loads `crypto/crypto.js` and `crypto/totp.js` from `../clavis-crypto/`.
- **src/util.c** — Base64 (standard + url-safe), URL encoding. - **src/util.c** — Base64 (standard + url-safe), URL encoding.
## Vendored dependencies ## Vendored dependencies
All in `vendor/`, no system package dependencies: All in `vendor/`, no system package dependencies:
- **BearSSL** — TLS, AES-GCM, HKDF, HMAC, PRNG - **BearSSL** — TLS, AES-GCM, HKDF, HMAC, PRNG
- **QuickJS** — JS runtime for shared crypto logic - **QuickJS** — JS runtime for shared crypto logic
- **cJSON** — JSON parsing - **cJSON** — JSON parsing
## Crypto design ## Crypto design
Three-tier encryption model: Three-tier encryption model:
- **L1** — first 8 bytes of L2 key, used as Bearer auth token - **L1** — first 8 bytes of L2 key, used as Bearer auth token
- **L2** — 16-byte AES-128-GCM key, client-side field encryption/decryption - **L2** — 16-byte AES-128-GCM key, client-side field encryption/decryption
- **L3** — requires hardware key (not handled by CLI) - **L3** — requires hardware key (not handled by CLI)
JS crypto in `../clavis-crypto/` is the single source of truth for encrypt/decrypt logic. The C code bridges BearSSL primitives into QuickJS so the same JS runs in CLI and browser. JS crypto in `../clavis-crypto/` is the single source of truth for encrypt/decrypt logic. The C code bridges BearSSL primitives into QuickJS so the same JS runs in CLI and browser.
## Token format ## Token format
`--token` value is a base64url-encoded, AES-GCM encrypted blob containing: `vault_host \0 agent_name \0 l2_key_16_bytes`. Decrypted using HKDF-derived key from seed `clavitor-l2-`. `--token` value is a base64url-encoded, AES-GCM encrypted blob containing: `vault_host \0 agent_name \0 l2_key_16_bytes`. Decrypted using HKDF-derived key from seed `clavitor-l2-`.
## Vault communication ## Vault communication
All API calls go to `https://<host>` (port 443 by default, override with `--port`) with `Authorization: Bearer <L1>` and `X-Agent: <agent_name>` headers. All API calls go to `https://<host>` (port 443 by default, override with `--port`) with `Authorization: Bearer <L1>` and `X-Agent: <agent_name>` headers.
Endpoints used: `/api/entries`, `/api/search?q=`, `/api/entries/<id>`, `/api/ext/totp/<id>`. Endpoints used: `/api/entries`, `/api/search?q=`, `/api/entries/<id>`, `/api/ext/totp/<id>`.
## ⚒️ Foundation First — No Mediocrity. Ever. ## ⚒️ Foundation First — No Mediocrity. Ever.
The rule is simple: do it right, or say something. The rule is simple: do it right, or say something.
Johan is an architect. Architects do not patch cracks in a bad foundation — they rebuild. Every agent on this team operates the same way. Johan is an architect. Architects do not patch cracks in a bad foundation — they rebuild. Every agent on this team operates the same way.
### What this means in practice ### What this means in practice
If you need three fixes for one problem, stop. Something fundamental is wrong. Name it, surface it — we fix that, not the symptom. If you need three fixes for one problem, stop. Something fundamental is wrong. Name it, surface it — we fix that, not the symptom.
If the code is spaghetti, say so. Do not add another workaround. The workaround is the problem now. If the code is spaghetti, say so. Do not add another workaround. The workaround is the problem now.
Quick fixes are not fixes. A "temporary" hack that ships is permanent. If it is not the right solution, it is the wrong solution. Quick fixes are not fixes. A "temporary" hack that ships is permanent. If it is not the right solution, it is the wrong solution.
Foundation > speed. A solid base makes everything downstream easy. A shaky base makes everything downstream a nightmare. We build bases. Foundation > speed. A solid base makes everything downstream easy. A shaky base makes everything downstream a nightmare. We build bases.
### The restart rule ### The restart rule
When the foundation is wrong: start over. Not "refactor slightly." Not "add an abstraction layer on top." Start over. This applies to code, infrastructure, design, encryption schemes, and written work alike. When the foundation is wrong: start over. Not "refactor slightly." Not "add an abstraction layer on top." Start over. This applies to code, infrastructure, design, encryption schemes, and written work alike.
### Q&D is research, not output ### Q&D is research, not output
Exploratory/throwaway work has its place — but it stays in research. Nothing Q&D ships. Nothing Q&D becomes the production path. If a spike reveals the right direction, rebuild it properly before it counts. Exploratory/throwaway work has its place — but it stays in research. Nothing Q&D ships. Nothing Q&D becomes the production path. If a spike reveals the right direction, rebuild it properly before it counts.
### When you hit a bad foundation ### When you hit a bad foundation
Call it out. Do not work around it. Bad foundations are not your fault — but silently building on them is. Surface the problem, we work on it together. Call it out. Do not work around it. Bad foundations are not your fault — but silently building on them is. Surface the problem, we work on it together.
The bar is high. The support is real. The bar is high. The support is real.
## Testing ## Testing
``` ```
./clavitor-cli test-crypto # BearSSL + JS crypto self-tests ./clavitor-cli test-crypto # BearSSL + JS crypto self-tests
./clavitor-cli test-totp <seed> # TOTP generation from base32 seed ./clavitor-cli test-totp <seed> # TOTP generation from base32 seed
./clavitor-cli test-roundtrip # runs crypto/test_crypto.js ./clavitor-cli test-roundtrip # runs crypto/test_crypto.js
``` ```

View File

@ -1,18 +1,13 @@
# clavis-crypto # clavis-crypto
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: clavis-crypto (this subproject). You are **Maria**. > **Deep reference:** [../../CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section V: clavis-crypto (your domain).
> **You are:** **Maria** — Run `./scripts/daily-review.sh` every morning. Fix failures first.
Shared cryptographic primitives used by every Clavitor client: browser frontend, CLI, browser extensions (Chrome/Firefox/Safari), mobile clients. The single source of truth for `encrypt_field`, `decrypt_field`, HKDF derivation, AES-GCM, and any other primitive that crosses target boundaries. Shared cryptographic primitives used by every Clavitor client: browser frontend, CLI, browser extensions (Chrome/Firefox/Safari), mobile clients. The single source of truth for `encrypt_field`, `decrypt_field`, HKDF derivation, AES-GCM, and any other primitive that crosses target boundaries.
## Hard rules specific to this subproject ## Hard rules specific to this subproject
- **Never diverge between targets.** If a primitive behaves differently in WebCrypto (browser/extensions) vs BearSSL (C CLI) vs platform-native (mobile), the bug is in `clavis-crypto` and it gets fixed here before any caller compensates. - **Never diverge between targets.** If a primitive behaves differently in WebCrypto (browser/extensions) vs BearSSL (C CLI) vs platform-native (mobile), the bug is in `clavis-crypto` and it gets fixed here before any caller compensates.
- **Bit-identical outputs are mandatory.** A field encrypted by the browser MUST decrypt cleanly in the CLI, and vice versa. This is verified by parity tests — if you change a primitive, run the parity tests against every target. - **Bit-identical outputs are mandatory.** A field encrypted by the browser MUST decrypt cleanly in the CLI, and vice versa. This is verified by parity tests — if you change a primitive, run the parity tests against every target.
- **No per-target shortcuts.** If a target's stdlib offers a faster path (e.g., a hardware-accelerated AES on iOS), use it ONLY if the parity tests confirm the output matches every other target byte-for-byte. - **No per-target shortcuts.** If a target's stdlib offers a faster path (e.g., a hardware-accelerated AES on iOS), use it ONLY if the parity tests confirm the output matches every other target byte-for-byte.
- **No silent fallback** when a primitive is unavailable. If a target lacks the required crypto support, fail loudly at startup, not silently at first use. - **No silent fallback** when a primitive is unavailable. If a target lacks the required crypto support, fail loudly at startup, not silently at first use.
## The daily check ## The daily check
Section III → D2 of `CLAVITOR-AGENT-HANDBOOK.md` enforces this with a `diff` between the browser and CLI `crypto.js` copies. Any divergence is a foundation alert. Section III → D2 of `CLAVITOR-AGENT-HANDBOOK.md` enforces this with a `diff` between the browser and CLI `crypto.js` copies. Any divergence is a foundation alert.
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → clavis-crypto for the full subproject contract.
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → clavis-crypto for the full subproject contract.

View File

@ -1,14 +1,11 @@
# clavis-firefox # clavis-firefox
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: Browser extensions (this subproject). You are **James**. > **Deep reference:** [../../CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section V: clavis-chrome/firefox/safari (your domain).
> **You are:** **James** — Run `./scripts/daily-review.sh` every morning. Fix failures first.
Firefox browser extension for Clavitor. Handles form detection, field filling, and the credential picker popup. Firefox browser extension for Clavitor. Handles form detection, field filling, and the credential picker popup.
## Hard rules specific to this subproject ## Hard rules specific to this subproject
- **Never store L2 or L3** in any extension storage area (`browser.storage.local`, `browser.storage.sync`, `browser.storage.session`). Active session keys live in background-script memory only and die on extension restart. - **Never store L2 or L3** in any extension storage area (`browser.storage.local`, `browser.storage.sync`, `browser.storage.session`). Active session keys live in background-script memory only and die on extension restart.
- **Never reimplement crypto.** Always use `clavis-crypto` / the canonical `crypto.js`. If the extension reimplements crypto, it WILL drift and corrupt fields encrypted by the browser frontend or the Chrome extension. - **Never reimplement crypto.** Always use `clavis-crypto` / the canonical `crypto.js`. If the extension reimplements crypto, it WILL drift and corrupt fields encrypted by the browser frontend or the Chrome extension.
- **Always HTTPS** to talk to the vault, even on localhost (self-signed cert in dev). Never plain HTTP. - **Always HTTPS** to talk to the vault, even on localhost (self-signed cert in dev). Never plain HTTP.
- **Permissions are minimal.** Match the Chrome extension's permission set as closely as possible — if it needs more, justify why in a comment. - **Permissions are minimal.** Match the Chrome extension's permission set as closely as possible — if it needs more, justify why in a comment.
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → Browser extensions for the full subproject contract.
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → Browser extensions for the full subproject contract.

View File

@ -1,13 +1,10 @@
# clavis-ios # clavis-ios
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: Mobile (this subproject). You are **Xiao** (晓). > **Deep reference:** [../../CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section V: clavis-android/ios (your domain).
> **You are:** **Xiao** — Run `./scripts/daily-review.sh` every morning. Fix failures first.
Native iOS client for Clavitor. Handles platform autofill integration and the credential picker UI. Native iOS client for Clavitor. Handles platform autofill integration and the credential picker UI.
## Hard rules specific to this subproject ## Hard rules specific to this subproject
- **Never implement crypto natively.** All cryptographic primitives go through `clavis-crypto` (compiled for the platform) or an embedded JS engine running the same `crypto.js` as the browser/CLI. Two crypto implementations on the same platform is a guaranteed drift. - **Never implement crypto natively.** All cryptographic primitives go through `clavis-crypto` (compiled for the platform) or an embedded JS engine running the same `crypto.js` as the browser/CLI. Two crypto implementations on the same platform is a guaranteed drift.
- **Never persist L2 or L3** to the iOS keychain or any platform storage. The session key lives in process memory; biometric unlock re-derives via PRF from iOS's WebAuthn / passkey APIs. - **Never persist L2 or L3** to the iOS keychain or any platform storage. The session key lives in process memory; biometric unlock re-derives via PRF from iOS's WebAuthn / passkey APIs.
- **Never** request entitlements beyond what's strictly required for autofill credentials. - **Never** request entitlements beyond what's strictly required for autofill credentials.
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → Mobile for the full subproject contract.
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → Mobile for the full subproject contract.

View File

@ -1,15 +1,12 @@
# clavis-safari # clavis-safari
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: Browser extensions (this subproject). You are **James**. > **Deep reference:** [../../CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section V: clavis-chrome/firefox/safari (your domain).
> **You are:** **James** — Run `./scripts/daily-review.sh` every morning. Fix failures first.
Safari browser extension for Clavitor. Handles form detection, field filling, and the credential picker popup. Distributed via the Safari Extensions infrastructure (App Store + Xcode-built container). Safari browser extension for Clavitor. Handles form detection, field filling, and the credential picker popup. Distributed via the Safari Extensions infrastructure (App Store + Xcode-built container).
## Hard rules specific to this subproject ## Hard rules specific to this subproject
- **Never store L2 or L3** in any extension storage area or the iCloud Keychain. Active session keys live in process memory only and die on extension restart. - **Never store L2 or L3** in any extension storage area or the iCloud Keychain. Active session keys live in process memory only and die on extension restart.
- **Never reimplement crypto.** Always use `clavis-crypto` / the canonical `crypto.js`. If the extension reimplements crypto, it WILL drift and corrupt fields encrypted by other clients. - **Never reimplement crypto.** Always use `clavis-crypto` / the canonical `crypto.js`. If the extension reimplements crypto, it WILL drift and corrupt fields encrypted by other clients.
- **Always HTTPS** to talk to the vault. Never plain HTTP. - **Always HTTPS** to talk to the vault. Never plain HTTP.
- **Container app exists only to host the extension.** Do not add unrelated functionality to the container — that's a Mac app and it's not what we're shipping. - **Container app exists only to host the extension.** Do not add unrelated functionality to the container — that's a Mac app and it's not what we're shipping.
- **Permissions are minimal.** Match the Chrome/Firefox extension permission set; if Safari requires something extra, justify it in a comment with the Safari API doc reference. - **Permissions are minimal.** Match the Chrome/Firefox extension permission set; if Safari requires something extra, justify it in a comment with the Safari API doc reference.
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → Browser extensions for the full subproject contract.
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → Browser extensions for the full subproject contract.

View File

@ -1,35 +1,23 @@
# clavis-telemetry # clavis-telemetry
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: clavis-telemetry (this subproject). You are **Hans**. > **Deep reference:** [../../CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section V: clavis-telemetry (your domain).
> **You are:** **Hans** — Run `./scripts/daily-review.sh` every morning. Fix failures first.
Operator telemetry: heartbeat metrics from POPs to central. CPU, memory, disk, vault count, request rates. Operational signals only — never user data. Operator telemetry: heartbeat metrics from POPs to central. CPU, memory, disk, vault count, request rates. Operational signals only — never user data.
## Hard rules specific to this subproject ## Hard rules specific to this subproject
- **Never send vault content.** Telemetry is operational, not data. No entry titles, no field values, no credential identifiers, no audit log entries that contain user information. - **Never send vault content.** Telemetry is operational, not data. No entry titles, no field values, no credential identifiers, no audit log entries that contain user information.
- **Never send raw user IP addresses.** Aggregate counts (e.g., `unique_ips_24h: 472`) are fine; raw IPs are not. - **Never send raw user IP addresses.** Aggregate counts (e.g., `unique_ips_24h: 472`) are fine; raw IPs are not.
- **Commercial-only by default.** Community edition is offline-by-default. Telemetry is opt-in for community installs and enforced-on for commercial POPs. Build tags must reflect this — community binaries should not even contain the telemetry code path. - **Commercial-only by default.** Community edition is offline-by-default. Telemetry is opt-in for community installs and enforced-on for commercial POPs. Build tags must reflect this — community binaries should not even contain the telemetry code path.
- **No phone-home for crashes.** If you ever want crash reporting, talk to Johan first. Auto-uploaded stack traces have leaked credentials in other products and we will not repeat that mistake. - **No phone-home for crashes.** If you ever want crash reporting, talk to Johan first. Auto-uploaded stack traces have leaked credentials in other products and we will not repeat that mistake.
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → clavis-telemetry for the full subproject contract. See `CLAVITOR-AGENT-HANDBOOK.md` Section V → clavis-telemetry for the full subproject contract.
## Operations ## Operations
### Log Retention ### Log Retention
Tarpit logs contain scanner IPs for security analysis. Rotate/delete per your organization's retention policy (recommended: 30 days). Tarpit logs contain scanner IPs for security analysis. Rotate/delete per your organization's retention policy (recommended: 30 days).
### External Alerting (Optional) ### External Alerting (Optional)
Outage alerts can be sent to ntfy. Configure via environment variables: Outage alerts can be sent to ntfy. Configure via environment variables:
- `NTFY_ALERT_URL` - The ntfy endpoint (e.g., `http://127.0.0.1:2586/clavitor-alerts`) - `NTFY_ALERT_URL` - The ntfy endpoint (e.g., `http://127.0.0.1:2586/clavitor-alerts`)
- `NTFY_ALERT_TOKEN` - Bearer token for authentication - `NTFY_ALERT_TOKEN` - Bearer token for authentication
If unset, outage logging continues without external notification. If unset, outage logging continues without external notification.
### Kuma Monitoring (Optional) ### Kuma Monitoring (Optional)
Health push to Kuma can be configured via: Health push to Kuma can be configured via:
- `KUMA_PUSH_URL` - Kuma push endpoint - `KUMA_PUSH_URL` - Kuma push endpoint
If unset, Kuma push is disabled.
If unset, Kuma push is disabled.

View File

@ -1,43 +1,25 @@
# Clavis Vault — CLAUDE.md # Clavis Vault — CLAUDE.md
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: clavis-vault (this subproject). You are **Sarah**. Run the Section III → Daily review checklist every morning. Drift gets fixed before any new feature work. > **Deep reference:** [../../CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section V: clavis-vault (your domain).
> **You are:** **Sarah** — Run `./scripts/daily-review.sh` every morning. Fix failures first.
## Foundation First — No Mediocrity. Ever. ## Foundation First — No Mediocrity. Ever.
The rule is simple: do it right, or say something. The rule is simple: do it right, or say something.
Johan is an architect. Architects do not patch cracks in a bad foundation — they rebuild. Every agent on this team operates the same way. Johan is an architect. Architects do not patch cracks in a bad foundation — they rebuild. Every agent on this team operates the same way.
### What this means in practice ### What this means in practice
If you need three fixes for one problem, stop. Something fundamental is wrong. Name it, surface it — we fix that, not the symptom. If you need three fixes for one problem, stop. Something fundamental is wrong. Name it, surface it — we fix that, not the symptom.
If the code is spaghetti, say so. Do not add another workaround. The workaround is the problem now. If the code is spaghetti, say so. Do not add another workaround. The workaround is the problem now.
Quick fixes are not fixes. A "temporary" hack that ships is permanent. If it is not the right solution, it is the wrong solution. Quick fixes are not fixes. A "temporary" hack that ships is permanent. If it is not the right solution, it is the wrong solution.
Foundation > speed. A solid base makes everything downstream easy. A shaky base makes everything downstream a nightmare. We build bases. Foundation > speed. A solid base makes everything downstream easy. A shaky base makes everything downstream a nightmare. We build bases.
### The restart rule ### The restart rule
When the foundation is wrong: start over. Not "refactor slightly." Not "add an abstraction layer on top." Start over. This applies to code, infrastructure, design, encryption schemes, and written work alike. When the foundation is wrong: start over. Not "refactor slightly." Not "add an abstraction layer on top." Start over. This applies to code, infrastructure, design, encryption schemes, and written work alike.
### Q&D is research, not output ### Q&D is research, not output
Exploratory/throwaway work has its place — but it stays in research. Nothing Q&D ships. Nothing Q&D becomes the production path. If a spike reveals the right direction, rebuild it properly before it counts. Exploratory/throwaway work has its place — but it stays in research. Nothing Q&D ships. Nothing Q&D becomes the production path. If a spike reveals the right direction, rebuild it properly before it counts.
### When you hit a bad foundation ### When you hit a bad foundation
Call it out. Do not work around it. Bad foundations are not your fault — but silently building on them is. Surface the problem, we work on it together. Call it out. Do not work around it. Bad foundations are not your fault — but silently building on them is. Surface the problem, we work on it together.
The bar is high. The support is real. The bar is high. The support is real.
--- ---
## Security Failures — NEVER HIDE THEM ## Security Failures — NEVER HIDE THEM
**The cardinal rule:** If decryption/verification fails, expose the failure. Never fall back to plaintext. Never silently continue. **The cardinal rule:** If decryption/verification fails, expose the failure. Never fall back to plaintext. Never silently continue.
### WRONG — Silent fallback (fireable offense) ### WRONG — Silent fallback (fireable offense)
```javascript ```javascript
try { try {
@ -46,7 +28,6 @@ try {
decrypted = plaintext; // NEVER DO THIS decrypted = plaintext; // NEVER DO THIS
} }
``` ```
### CORRECT — Visible failure ### CORRECT — Visible failure
```javascript ```javascript
try { try {
@ -55,24 +36,17 @@ try {
decrypted = '[decryption failed]'; // User sees the failure decrypted = '[decryption failed]'; // User sees the failure
} }
``` ```
This applies to: This applies to:
- Encryption/decryption errors - Encryption/decryption errors
- Signature verification failures - Signature verification failures
- Authentication failures - Authentication failures
- Tampering detection - Tampering detection
- Any security-critical operation - Any security-critical operation
**Security failures must be noisy, visible, and blocking — never silent, hidden, or permissive.** **Security failures must be noisy, visible, and blocking — never silent, hidden, or permissive.**
See `SECURITY.md` for full principles. See `SECURITY.md` for full principles.
--- ---
## Edition System (Community vs Commercial) ## Edition System (Community vs Commercial)
Clavitor Vault has two editions with build-time separation: Clavitor Vault has two editions with build-time separation:
### Community Edition (Default) ### Community Edition (Default)
```bash ```bash
go build -o clavitor ./cmd/clavitor/ go build -o clavitor ./cmd/clavitor/
@ -81,7 +55,6 @@ go build -o clavitor ./cmd/clavitor/
- Local logging only - Local logging only
- Self-hosted - Self-hosted
- Elastic License 2.0 - Elastic License 2.0
### Commercial Edition ### Commercial Edition
```bash ```bash
go build -tags commercial -o clavitor ./cmd/clavitor/ go build -tags commercial -o clavitor ./cmd/clavitor/
@ -90,27 +63,18 @@ go build -tags commercial -o clavitor ./cmd/clavitor/
- Operator alerts POST to `/v1/alerts` - Operator alerts POST to `/v1/alerts`
- Multi-POP management - Multi-POP management
- Commercial license - Commercial license
### Using the Edition Package ### Using the Edition Package
```go ```go
import "github.com/johanj/clavitor/edition" import "github.com/johanj/clavitor/edition"
// Send operator alerts (works in both editions) // Send operator alerts (works in both editions)
edition.Current.AlertOperator(ctx, "auth_error", "message", details) edition.Current.AlertOperator(ctx, "auth_error", "message", details)
// Check edition // Check edition
currentEdition := edition.Current.Name() // "community" or "commercial" currentEdition := edition.Current.Name() // "community" or "commercial"
``` ```
See `edition/CLAUDE.md` for full documentation. See `edition/CLAUDE.md` for full documentation.
--- ---
## Clavitor Vault v2 — Current State & Testing ## Clavitor Vault v2 — Current State & Testing
### What we built this session ### What we built this session
#### 1. Domain classification for import scopes #### 1. Domain classification for import scopes
- Import page (`cmd/clavitor/web/import.html`) parses 14+ password manager formats client-side - Import page (`cmd/clavitor/web/import.html`) parses 14+ password manager formats client-side
- Unique domains are extracted (eTLD+1) and sent to `https://clavitor.ai/classify` - Unique domains are extracted (eTLD+1) and sent to `https://clavitor.ai/classify`
@ -119,7 +83,6 @@ See `edition/CLAUDE.md` for full documentation.
- Domains with no URL get scope "unclassified" (not "misc"). "misc" = LLM tried and failed - Domains with no URL get scope "unclassified" (not "misc"). "misc" = LLM tried and failed
- Domains are sent in chunks of 200 to stay within token limits - Domains are sent in chunks of 200 to stay within token limits
- Classification is opt-in: user sees consent dialog with Yes/Skip/Cancel - Classification is opt-in: user sees consent dialog with Yes/Skip/Cancel
#### 2. Import flow UX #### 2. Import flow UX
- Drop file → parse → hide file step → consent dialog (Yes/Skip/Cancel) - Drop file → parse → hide file step → consent dialog (Yes/Skip/Cancel)
- Cancel returns to file step - Cancel returns to file step
@ -129,7 +92,6 @@ See `edition/CLAUDE.md` for full documentation.
- Black entry icons (LGN/CARD/NOTE) with white text — on brand - Black entry icons (LGN/CARD/NOTE) with white text — on brand
- Global black checkboxes (`accent-color: var(--text)`) - Global black checkboxes (`accent-color: var(--text)`)
- Unified CSS classes: `.item-row`, `.item-icon`, `.item-list` (replacing import-specific classes) - Unified CSS classes: `.item-row`, `.item-icon`, `.item-list` (replacing import-specific classes)
#### 3. Import filtering visibility (NEW) #### 3. Import filtering visibility (NEW)
- Import parsers now track what gets filtered and why - Import parsers now track what gets filtered and why
- `importers-parsers.js` has `_importReport` object that records: `rawCount`, `filtered[]`, `finalCount` - `importers-parsers.js` has `_importReport` object that records: `rawCount`, `filtered[]`, `finalCount`
@ -138,7 +100,6 @@ See `edition/CLAUDE.md` for full documentation.
- Filter badge with tooltip showing breakdown: `"Filtered: 150 duplicate, 97 alias, 12 trashed"` - Filter badge with tooltip showing breakdown: `"Filtered: 150 duplicate, 97 alias, 12 trashed"`
- Clicking the filtered badge shows detailed list of what was skipped - Clicking the filtered badge shows detailed list of what was skipped
- **Why**: User saw 1073 during import but only 818 in vault. Now they can see the ~250 records were: duplicates (older versions), email aliases, and trashed items. - **Why**: User saw 1073 during import but only 818 in vault. Now they can see the ~250 records were: duplicates (older versions), email aliases, and trashed items.
#### 4. Credential Alternates System (NEW) #### 4. Credential Alternates System (NEW)
- **Problem**: Chrome/Firefox imports don't have modification dates, so we can't tell which password is newer. Same site+user from different sources would overwrite each other. - **Problem**: Chrome/Firefox imports don't have modification dates, so we can't tell which password is newer. Same site+user from different sources would overwrite each other.
- **Solution**: Multiple passwords per site+user are now stored as "alternates" instead of overwriting. - **Solution**: Multiple passwords per site+user are now stored as "alternates" instead of overwriting.
@ -151,7 +112,6 @@ See `edition/CLAUDE.md` for full documentation.
- `GET /ext/match?url=...` now returns alternates array sorted by verified_at (verified first) - `GET /ext/match?url=...` now returns alternates array sorted by verified_at (verified first)
- **CLI Protocol**: When multiple passwords for same site+user, try verified ones first. On success, call `/worked` endpoint. Backend marks winner as verified and links alternates to it. - **CLI Protocol**: When multiple passwords for same site+user, try verified ones first. On success, call `/worked` endpoint. Backend marks winner as verified and links alternates to it.
- **Import UI**: Shows `"Done — 50 imported, 12 alternates"` so user knows some were stored as alternates. - **Import UI**: Shows `"Done — 50 imported, 12 alternates"` so user knows some were stored as alternates.
#### 5. Security hardening (IN PROGRESS — needs testing) #### 5. Security hardening (IN PROGRESS — needs testing)
- **List endpoint stripped**: GET /api/entries now always returns metadata only (title, type, scopes, entry_id). No data blobs, no ?meta=1 toggle. Full entry data only via GET /api/entries/{id} with scope enforcement. - **List endpoint stripped**: GET /api/entries now always returns metadata only (title, type, scopes, entry_id). No data blobs, no ?meta=1 toggle. Full entry data only via GET /api/entries/{id} with scope enforcement.
- **Agent system type guard**: Agents cannot create/update entries with type=agent or type=scope. Enforced on CreateEntry, CreateEntryBatch, UpsertEntry, UpdateEntry. - **Agent system type guard**: Agents cannot create/update entries with type=agent or type=scope. Enforced on CreateEntry, CreateEntryBatch, UpsertEntry, UpdateEntry.
@ -159,11 +119,8 @@ See `edition/CLAUDE.md` for full documentation.
- **Per-agent IP whitelist**: Stored in agent entry (L1-encrypted). Empty on creation → filled with IP from first contact → enforced on every subsequent request. Supports CIDRs (10.0.0.0/16), exact IPs, and FQDNs (home.smith.family), comma-separated. - **Per-agent IP whitelist**: Stored in agent entry (L1-encrypted). Empty on creation → filled with IP from first contact → enforced on every subsequent request. Supports CIDRs (10.0.0.0/16), exact IPs, and FQDNs (home.smith.family), comma-separated.
- **Per-agent rate limiting**: Configurable requests/minute per agent ID (not per IP). Stored in agent entry. - **Per-agent rate limiting**: Configurable requests/minute per agent ID (not per IP). Stored in agent entry.
- **Admin operations require PRF tap**: Agent CRUD and scope updates require a fresh WebAuthn assertion. Flow: POST /auth/admin/begin → PRF tap → POST /auth/admin/complete → one-time admin token in X-Admin-Token header → pass to admin endpoint. Token is single-use, 5-minute expiry. - **Admin operations require PRF tap**: Agent CRUD and scope updates require a fresh WebAuthn assertion. Flow: POST /auth/admin/begin → PRF tap → POST /auth/admin/complete → one-time admin token in X-Admin-Token header → pass to admin endpoint. Token is single-use, 5-minute expiry.
### What is semi-done / needs testing ### What is semi-done / needs testing
The security hardening code compiles and the vault runs, but none of it has been tested with actual agent tokens or WebAuthn assertions yet. Specifically: The security hardening code compiles and the vault runs, but none of it has been tested with actual agent tokens or WebAuthn assertions yet. Specifically:
1. **IP whitelist first-contact fill**: ✅ Fixed - DB errors now return 500 1. **IP whitelist first-contact fill**: ✅ Fixed - DB errors now return 500
2. **IP whitelist enforcement**: Does CIDR matching work? FQDN resolution? Comma-separated lists? FQDN now has 5-min cache 2. **IP whitelist enforcement**: Does CIDR matching work? FQDN resolution? Comma-separated lists? FQDN now has 5-min cache
3. **Per-agent rate limiter**: Does it correctly track per agent ID and reset per minute? 3. **Per-agent rate limiter**: Does it correctly track per agent ID and reset per minute?
@ -171,30 +128,22 @@ The security hardening code compiles and the vault runs, but none of it has been
5. **System type guards**: ✅ Fixed - Agents blocked entirely from batch import; returns 403 on forbidden types 5. **System type guards**: ✅ Fixed - Agents blocked entirely from batch import; returns 403 on forbidden types
6. **L3 field preservation**: ✅ Fixed - Agents cannot overwrite L3 fields in batch or upsert 6. **L3 field preservation**: ✅ Fixed - Agents cannot overwrite L3 fields in batch or upsert
7. **List endpoint**: Verify no data blobs leak. Check browser console: entries[0] should have no data or fields property. 7. **List endpoint**: Verify no data blobs leak. Check browser console: entries[0] should have no data or fields property.
### Known Issues (Accepted) ### Known Issues (Accepted)
**IP Whitelist Race Condition**: There is a theoretical race on first-contact IP recording if two parallel requests from different IPs arrive simultaneously. This was reviewed and accepted because: **IP Whitelist Race Condition**: There is a theoretical race on first-contact IP recording if two parallel requests from different IPs arrive simultaneously. This was reviewed and accepted because:
- Requires a stolen agent token (already a compromise) - Requires a stolen agent token (already a compromise)
- Requires racing first contact from two different IPs - Requires racing first contact from two different IPs
- The "loser" simply won't be auto-whitelisted - The "loser" simply won't be auto-whitelisted
- Cannot be reproduced in testing; practically impossible to trigger - Cannot be reproduced in testing; practically impossible to trigger
- Fix would require plaintext column + atomic update (not worth complexity) - Fix would require plaintext column + atomic update (not worth complexity)
See comment in `api/middleware.go` for full rationale. See comment in `api/middleware.go` for full rationale.
**Admin Token Consumed Early**: The admin token is consumed immediately upon validation in `requireAdmin()`. If the subsequent operation fails (DB error, validation error, etc.), the token is gone but the operation didn't complete. The user must perform a fresh PRF tap to retry. **Admin Token Consumed Early**: The admin token is consumed immediately upon validation in `requireAdmin()`. If the subsequent operation fails (DB error, validation error, etc.), the token is gone but the operation didn't complete. The user must perform a fresh PRF tap to retry.
This was reviewed and accepted because: This was reviewed and accepted because:
- 5-10 minute token lifetime makes re-auth acceptable - 5-10 minute token lifetime makes re-auth acceptable
- It's a UX inconvenience, not a security vulnerability - It's a UX inconvenience, not a security vulnerability
- Deferring consumption until operation success would require transaction-like complexity - Deferring consumption until operation success would require transaction-like complexity
- Rare edge case: requires admin operation to fail after token validation - Rare edge case: requires admin operation to fail after token validation
### How testing works ### How testing works
No automated test suite for this session's work. Testing is manual via the browser: No automated test suite for this session's work. Testing is manual via the browser:
1. Vault runs locally on forge (this machine) at port 1984, accessed via https://dev.clavitor.ai/app/ 1. Vault runs locally on forge (this machine) at port 1984, accessed via https://dev.clavitor.ai/app/
2. Caddy on 192.168.0.2 reverse-proxies dev.clavitor.ai → forge:1984 2. Caddy on 192.168.0.2 reverse-proxies dev.clavitor.ai → forge:1984
3. Import testing: Drop a Proton Pass ZIP export (or any of the 14 supported formats) on the import page. Check scope pills, counts, classifications, and **filtered count badge** — shows why records were skipped (duplicates, aliases, trashed). 3. Import testing: Drop a Proton Pass ZIP export (or any of the 14 supported formats) on the import page. Check scope pills, counts, classifications, and **filtered count badge** — shows why records were skipped (duplicates, aliases, trashed).
@ -202,9 +151,7 @@ No automated test suite for this session's work. Testing is manual via the brows
5. Screen capture: `/capture` skill takes a live screenshot from Johan's Mac (display 3). `/screenshot` fetches the latest manual screenshot. 5. Screen capture: `/capture` skill takes a live screenshot from Johan's Mac (display 3). `/screenshot` fetches the latest manual screenshot.
6. Version verification: The topbar shows the **build timestamp** (e.g., `2026-04-04-1432`) fetched from `/api/version`. If the timestamp doesn't update after `make dev`, the old binary is still running — check `make status`. 6. Version verification: The topbar shows the **build timestamp** (e.g., `2026-04-04-1432`) fetched from `/api/version`. If the timestamp doesn't update after `make dev`, the old binary is still running — check `make status`.
7. DB location: Vault data is in `/home/johan/dev/clavitor/clavis/clavis-vault/data/`. Delete clavitor-* files there to start fresh (will require passkey re-registration). 7. DB location: Vault data is in `/home/johan/dev/clavitor/clavis/clavis-vault/data/`. Delete clavitor-* files there to start fresh (will require passkey re-registration).
### Key files ### Key files
| File | What | | File | What |
|------|------| |------|------|
| api/handlers.go | All HTTP handlers, security guards, admin auth | | api/handlers.go | All HTTP handlers, security guards, admin auth |
@ -218,22 +165,17 @@ No automated test suite for this session's work. Testing is manual via the brows
| cmd/clavitor/web/topbar.js | Version number, nav, idle timer | | cmd/clavitor/web/topbar.js | Version number, nav, idle timer |
| cmd/clavitor/web/clavitor-app.css | All styles, item-row/item-icon system | | cmd/clavitor/web/clavitor-app.css | All styles, item-row/item-icon system |
| clavitor.ai/main.go | Portal + /classify endpoint (Haiku on OpenRouter) | | clavitor.ai/main.go | Portal + /classify endpoint (Haiku on OpenRouter) |
### Deploy Clavitor Vault (dev) ### Deploy Clavitor Vault (dev)
Working directory: `/home/johan/dev/clavitor/clavis/clavis-vault` Working directory: `/home/johan/dev/clavitor/clavis/clavis-vault`
**Prerequisites:** **Prerequisites:**
```bash ```bash
# Enable user systemd services (one-time setup) # Enable user systemd services (one-time setup)
systemctl --user enable --now clavitor.service systemctl --user enable --now clavitor.service
``` ```
**Build and deploy (one command):** **Build and deploy (one command):**
```bash ```bash
make dev # stop → build → start (graceful shutdown via SIGTERM) make dev # stop → build → start (graceful shutdown via SIGTERM)
``` ```
**Individual commands:** **Individual commands:**
```bash ```bash
make stop # systemctl --user stop clavitor.service make stop # systemctl --user stop clavitor.service
@ -243,40 +185,25 @@ make status # systemctl --user status clavitor.service
make logs # journalctl --user -u clavitor -f make logs # journalctl --user -u clavitor -f
make build # go build... make build # go build...
``` ```
**Service file location:** `~/.config/systemd/user/clavitor.service` **Service file location:** `~/.config/systemd/user/clavitor.service`
Caddy on 192.168.0.2 reverse-proxies dev.clavitor.ai → forge:1984 (self-signed, so tls_insecure_skip_verify). Caddy on 192.168.0.2 reverse-proxies dev.clavitor.ai → forge:1984 (self-signed, so tls_insecure_skip_verify).
**Update Caddy config:** **Update Caddy config:**
```bash ```bash
ssh root@192.168.0.2 ssh root@192.168.0.2
# Edit /etc/caddy/Caddyfile, then: # Edit /etc/caddy/Caddyfile, then:
systemctl reload caddy systemctl reload caddy
``` ```
Web files are embedded at compile time (go:embed). CSS/JS/HTML changes require rebuild. Web files are embedded at compile time (go:embed). CSS/JS/HTML changes require rebuild.
Bump version in `cmd/clavitor/web/topbar.js` (search for v2.0.) to verify new build is live. Bump version in `cmd/clavitor/web/topbar.js` (search for v2.0.) to verify new build is live.
### Deploy clavitor.ai (prod) ### Deploy clavitor.ai (prod)
Working directory: `/home/johan/dev/clavitor/clavitor.ai` Working directory: `/home/johan/dev/clavitor/clavitor.ai`
```bash ```bash
make deploy-prod make deploy-prod
``` ```
This cross-compiles, SCPs to Zürich, enters maintenance mode, restarts systemd, exits maintenance. One command. This cross-compiles, SCPs to Zürich, enters maintenance mode, restarts systemd, exits maintenance. One command.
SSH: root@clavitor.ai — port 22 blocked on public IP, use Tailscale. Never use johan@. Avoid rapid SSH attempts (fail2ban will lock you out — it already happened once this session). SSH: root@clavitor.ai — port 22 blocked on public IP, use Tailscale. Never use johan@. Avoid rapid SSH attempts (fail2ban will lock you out — it already happened once this session).
Env vars are in `/opt/clavitor-web/.env` and `/etc/systemd/system/clavitor-web.service`. After changing .env, run `systemctl daemon-reload && systemctl restart clavitor-web` on the server. Env vars are in `/opt/clavitor-web/.env` and `/etc/systemd/system/clavitor-web.service`. After changing .env, run `systemctl daemon-reload && systemctl restart clavitor-web` on the server.
**NEVER deploy the database. Only the binary gets uploaded. The SQLite DB on prod is the source of truth.** **NEVER deploy the database. Only the binary gets uploaded. The SQLite DB on prod is the source of truth.**
Verify: `ssh root@<tailscale-ip> "systemctl status clavitor-web"` Verify: `ssh root@<tailscale-ip> "systemctl status clavitor-web"`
### IMPORTANT ### IMPORTANT
**NEVER deploy to prod without Johan's explicit approval. This caused a SEV-1 on 2026-03-29.**
**NEVER deploy to prod without Johan's explicit approval. This caused a SEV-1 on 2026-03-29.**

View File

@ -1,26 +1,19 @@
# Clavitor Website — clavitor.com # Clavitor Website — clavitor.com
> **Quickstart (60s):** [../QUICKSTART.md](../QUICKSTART.md) — who you are, 4 things to do, critical rules.
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: clavitor.ai/admin (this subproject). You are **Emma**. > **Deep reference:** [../CLAVITOR-AGENT-HANDBOOK.md](../CLAVITOR-AGENT-HANDBOOK.md) — Section V: clavitor.ai (your domain).
> **You are:** **Emma** — Run `./scripts/daily-review.sh` every morning. Fix failures first.
## Foundation First — No Mediocrity. Ever. ## Foundation First — No Mediocrity. Ever.
The rule is simple: do it right, or say something. The rule is simple: do it right, or say something.
Johan is an architect. Architects do not patch cracks in a bad foundation — they rebuild. Every agent on this team operates the same way. Johan is an architect. Architects do not patch cracks in a bad foundation — they rebuild. Every agent on this team operates the same way.
**What this means in practice:** **What this means in practice:**
- If you need three fixes for one problem, stop. Something fundamental is wrong. Name it, surface it — we fix that, not the symptom. - If you need three fixes for one problem, stop. Something fundamental is wrong. Name it, surface it — we fix that, not the symptom.
- If the code is spaghetti, say so. Do not add another workaround. The workaround is the problem now. - If the code is spaghetti, say so. Do not add another workaround. The workaround is the problem now.
- Quick fixes are not fixes. A "temporary" hack that ships is permanent. If it is not the right solution, it is the wrong solution. - Quick fixes are not fixes. A "temporary" hack that ships is permanent. If it is not the right solution, it is the wrong solution.
- Foundation > speed. A solid base makes everything downstream easy. A shaky base makes everything downstream a nightmare. We build bases. - Foundation > speed. A solid base makes everything downstream easy. A shaky base makes everything downstream a nightmare. We build bases.
**The restart rule:** When the foundation is wrong: start over. Not "refactor slightly." Not "add an abstraction layer on top." Start over. This applies to code, infrastructure, design, encryption schemes, and written work alike. **The restart rule:** When the foundation is wrong: start over. Not "refactor slightly." Not "add an abstraction layer on top." Start over. This applies to code, infrastructure, design, encryption schemes, and written work alike.
**Q&D is research, not output:** Exploratory/throwaway work has its place — but it stays in research. Nothing Q&D ships. Nothing Q&D becomes the production path. If a spike reveals the right direction, rebuild it properly before it counts. **Q&D is research, not output:** Exploratory/throwaway work has its place — but it stays in research. Nothing Q&D ships. Nothing Q&D becomes the production path. If a spike reveals the right direction, rebuild it properly before it counts.
**When you hit a bad foundation:** Call it out. Do not work around it. Bad foundations are not your fault — but silently building on them is. Surface the problem, we work on it together. **When you hit a bad foundation:** Call it out. Do not work around it. Bad foundations are not your fault — but silently building on them is. Surface the problem, we work on it together.
The bar is high. The support is real. These rules apply to you now. The bar is high. The support is real. These rules apply to you now.
## Architecture ## Architecture
- Go web server (`main.go`) with `go:embed` for templates, CSS, SVGs, PNGs - Go web server (`main.go`) with `go:embed` for templates, CSS, SVGs, PNGs
- Templates in `templates/*.tmpl`, single CSS in `clavitor.css` - Templates in `templates/*.tmpl`, single CSS in `clavitor.css`
@ -28,40 +21,33 @@ The bar is high. The support is real. These rules apply to you now.
- Dev mode: auto-detected when `templates/` dir exists on disk — reloads templates per request, but CSS/SVGs require rebuild (`go:embed`) - Dev mode: auto-detected when `templates/` dir exists on disk — reloads templates per request, but CSS/SVGs require rebuild (`go:embed`)
- Port 8099 - Port 8099
- License: Elastic License 2.0 (NOT MIT) - License: Elastic License 2.0 (NOT MIT)
## Deployment ## Deployment
### Dev (forge = 192.168.1.16, Florida — dev.clavitor.ai) ### Dev (forge = 192.168.1.16, Florida — dev.clavitor.ai)
``` ```
make dev # build + restart locally make dev # build + restart locally
make deploy-dev # same thing make deploy-dev # same thing
``` ```
Dev runs on forge (localhost). `dev.clavitor.ai` DNS points to home IP. Dev runs on forge (localhost). `dev.clavitor.ai` DNS points to home IP.
### Prod (Zürich — clavitor.ai — clavitor.ai) ### Prod (Zürich — clavitor.ai — clavitor.ai)
``` ```
make deploy-prod # cross-compile amd64, scp to Zürich, restart systemd make deploy-prod # cross-compile amd64, scp to Zürich, restart systemd
``` ```
Prod runs at `/opt/clavitor-web/` as systemd service `clavitor-web`. Prod runs at `/opt/clavitor-web/` as systemd service `clavitor-web`.
Caddy reverse proxies `clavitor.ai`, `clavitor.com`, `www.clavitor.ai`, `www.clavitor.com``localhost:8099`. Caddy reverse proxies `clavitor.ai`, `clavitor.com`, `www.clavitor.ai`, `www.clavitor.com``localhost:8099`.
### First-time setup (already done) ### First-time setup (already done)
``` ```
make setup-prod # creates /opt/clavitor-web, systemd service, uploads binary+db make setup-prod # creates /opt/clavitor-web, systemd service, uploads binary+db
``` ```
Then manually update `/etc/caddy/Caddyfile` to reverse_proxy. Then manually update `/etc/caddy/Caddyfile` to reverse_proxy.
### SSH ### SSH
- Prod: `ssh root@clavitor.ai` - Prod: `ssh root@clavitor.ai`
- Tailscale: `zurich` (100.70.148.118) — SSH may be blocked via Tailscale - Tailscale: `zurich` (100.70.148.118) — SSH may be blocked via Tailscale
## Build & Run ## Build & Run
``` ```
CGO_ENABLED=1 go build -o clavitor-web . CGO_ENABLED=1 go build -o clavitor-web .
./clavitor-web ./clavitor-web
``` ```
CSS and SVG changes require rebuild (embedded at compile time). Template changes reload in dev mode. CSS and SVG changes require rebuild (embedded at compile time). Template changes reload in dev mode.
## Brand & Design ## Brand & Design
- Light mode only. Single source of truth: `clavitor.css` - Light mode only. Single source of truth: `clavitor.css`
- Logo: the black square (`#0A0A0A`). favicon.svg = black square - Logo: the black square (`#0A0A0A`). favicon.svg = black square
@ -71,27 +57,23 @@ CSS and SVG changes require rebuild (embedded at compile time). Template changes
- Fonts: Figtree (body), JetBrains Mono (code/monospace) - Fonts: Figtree (body), JetBrains Mono (code/monospace)
- No inline styles, no CSS in templates. Everything in clavitor.css. - No inline styles, no CSS in templates. Everything in clavitor.css.
- Always capitalize "Clavitor" in prose. Lowercase in code/paths/commands. - Always capitalize "Clavitor" in prose. Lowercase in code/paths/commands.
## Encryption Terminology ## Encryption Terminology
- **Vault Encryption** — whole vault at rest - **Vault Encryption** — whole vault at rest
- **Credential Encryption** — per-field, server-side (AI agents can read via CLI) - **Credential Encryption** — per-field, server-side (AI agents can read via CLI)
- **Identity Encryption** — per-field, client-side via WebAuthn PRF (Touch ID only, server cannot decrypt) - **Identity Encryption** — per-field, client-side via WebAuthn PRF (Touch ID only, server cannot decrypt)
- Never use "sealed fields", "agent fields", "L1", "L2", "L3" - Never use "sealed fields", "agent fields", "L1", "L2", "L3"
- Agents use CLI, NOT MCP (MCP exposes plaintext; CLI is scoped) - Agents use CLI, NOT MCP (MCP exposes plaintext; CLI is scoped)
## POPs (Points of Presence) ## POPs (Points of Presence)
- Stored in `pops` table in clavitor.db — the single source of truth - Stored in `pops` table in clavitor.db — the single source of truth
- Map on /hosted is generated dynamically from DB via JavaScript - Map on /hosted is generated dynamically from DB via JavaScript
- Zürich = HQ, black dot, larger (11×11). Live POPs = red. Planned = light red. - Zürich = HQ, black dot, larger (11×11). Live POPs = red. Planned = light red.
- "You" visitor dot = circle (not square — "you" is not clavitor) - "You" visitor dot = circle (not square — "you" is not clavitor)
## Key URLs ## Key URLs
- `/hosted` — hosted product page with dynamic world map - `/hosted` — hosted product page with dynamic world map
- `/glass` — looking glass (latency from user's browser) - `/glass` — looking glass (latency from user's browser)
- `/noc?pin=250365` — NOC dashboard (telemetry, read-only, hardcoded PIN) - `/noc?pin=250365` — NOC dashboard (telemetry, read-only, hardcoded PIN)
- `/telemetry` — POST endpoint for POP agent heartbeats (no auth) - `/telemetry` — POST endpoint for POP agent heartbeats (no auth)
- `/ping` — server-side TCP ping (for diagnostics) - `/ping` — server-side TCP ping (for diagnostics)
## Vault Binary ## Vault Binary
- Source: `~/dev/clavitor/clovis/clovis-vault/` - Source: `~/dev/clavitor/clovis/clovis-vault/`
- Build for ARM64: `cd ~/dev/clavitor/clovis/clovis-vault && GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o clavitor-linux-arm64 ./cmd/clavitor` - Build for ARM64: `cd ~/dev/clavitor/clovis/clovis-vault && GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o clavitor-linux-arm64 ./cmd/clavitor`
@ -99,10 +81,9 @@ CSS and SVG changes require rebuild (embedded at compile time). Template changes
- Vault runs on port 1984 with TLS - Vault runs on port 1984 with TLS
- Has `/ping` endpoint (11 bytes, no DB, CORS via middleware) for looking glass - Has `/ping` endpoint (11 bytes, no DB, CORS via middleware) for looking glass
- Has `/health` endpoint (heavier, queries DB) - Has `/health` endpoint (heavier, queries DB)
## Providers ## Providers
- AWS: most POPs (free tier t4g.micro) - AWS: most POPs (free tier t4g.micro)
- LightNode: Santiago, Bogotá, Manila, Dhaka - LightNode: Santiago, Bogotá, Manila, Dhaka
- ishosting: Istanbul, Almaty - ishosting: Istanbul, Almaty
- HostAfrica: Lagos, Nairobi - HostAfrica: Lagos, Nairobi
- Rackmill: Perth - Rackmill: Perth

View File

@ -1,25 +1,19 @@
# clavitor.ai/admin — central admin / Paddle integration # clavitor.ai/admin — central admin / Paddle integration
> **Quickstart (60s):** [../QUICKSTART.md](../QUICKSTART.md) — who you are, 4 things to do, critical rules.
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: clavitor.ai/admin (this subproject). You are **Emma**. > **Deep reference:** [../CLAVITOR-AGENT-HANDBOOK.md](../CLAVITOR-AGENT-HANDBOOK.md) — Section V: clavitor.ai (your domain).
> **You are:** **Emma** — Run `./scripts/daily-review.sh` every morning. Fix failures first.
Central admin service. Owns the customer hierarchy (MSP → end-customer → vault slots), the seat ledger, the Paddle webhook handler, and the vault registry mapping `(customer, slot_index, l0, pop)`. This is the directory service — not a vault. Central admin service. Owns the customer hierarchy (MSP → end-customer → vault slots), the seat ledger, the Paddle webhook handler, and the vault registry mapping `(customer, slot_index, l0, pop)`. This is the directory service — not a vault.
## Hard rules specific to this subproject ## Hard rules specific to this subproject
- **Never hold any decryption material.** Central is not a vault. The wrapped L3 stored centrally for distribution is opaque to central — no L3, no L2, no L1, no master_key, ever. If you find yourself wanting to decrypt vault content here, you are in the wrong process. - **Never hold any decryption material.** Central is not a vault. The wrapped L3 stored centrally for distribution is opaque to central — no L3, no L2, no L1, no master_key, ever. If you find yourself wanting to decrypt vault content here, you are in the wrong process.
- **Never trust an inbound webhook without verifying its HMAC signature.** Paddle webhook verification is mandatory. The secret comes from `PADDLE_WEBHOOK_SECRET`. If the env var is unset, every webhook is refused. There is no debug bypass. - **Never trust an inbound webhook without verifying its HMAC signature.** Paddle webhook verification is mandatory. The secret comes from `PADDLE_WEBHOOK_SECRET`. If the env var is unset, every webhook is refused. There is no debug bypass.
- **Never accept admin operations from outside Tailscale.** The `vaults/claim`, `issue-token`, `wl3/since`, `wl3/full` endpoints listen only on the tailnet interface. Public clavitor.ai serves users; the ops control plane is invisible to the internet. - **Never accept admin operations from outside Tailscale.** The `vaults/claim`, `issue-token`, `wl3/since`, `wl3/full` endpoints listen only on the tailnet interface. Public clavitor.ai serves users; the ops control plane is invisible to the internet.
- **Never expose the Paddle API key, webhook secret, or any service credentials in client-side code.** Server-side env only. - **Never expose the Paddle API key, webhook secret, or any service credentials in client-side code.** Server-side env only.
- **Never delete vault data, WL3 files, or audit logs without an explicit GDPR request.** The default lifetime is forever. Cancellation/downgrade marks slots `archived`; only an explicit one-shot deletion script touches the underlying files. - **Never delete vault data, WL3 files, or audit logs without an explicit GDPR request.** The default lifetime is forever. Cancellation/downgrade marks slots `archived`; only an explicit one-shot deletion script touches the underlying files.
## Vault slot lifecycle (canonical) ## Vault slot lifecycle (canonical)
Pre-create at subscription time: Pre-create at subscription time:
1. Customer subscribes to a plan with N seats → `INSERT INTO vault_slots` N rows, all `status='unused'`. 1. Customer subscribes to a plan with N seats → `INSERT INTO vault_slots` N rows, all `status='unused'`.
2. Owner names a slot ("Anna") and clicks "invite" → status moves to `pending`, central calls the POP's `/admin/issue-token` over Tailscale, POP returns the 6-char token, central displays it to the owner. 2. Owner names a slot ("Anna") and clicks "invite" → status moves to `pending`, central calls the POP's `/admin/issue-token` over Tailscale, POP returns the 6-char token, central displays it to the owner.
3. Anna enrolls at the POP → status moves to `active`, `l0` populated, `enrolled_at` set. 3. Anna enrolls at the POP → status moves to `active`, `l0` populated, `enrolled_at` set.
4. Cancellation/downgrade → status moves to `archived`. Vault data and WL3 file persist. 4. Cancellation/downgrade → status moves to `archived`. Vault data and WL3 file persist.
Plan upgrade = `INSERT` more `unused` rows. Plan downgrade = refuse until the owner manually marks excess slots `archived` (no silent data loss). Plan upgrade = `INSERT` more `unused` rows. Plan downgrade = refuse until the owner manually marks excess slots `archived` (no silent data loss).
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → clavitor.ai/admin for the full subproject contract.
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → clavitor.ai/admin for the full subproject contract.

View File

@ -0,0 +1,172 @@
# Git Hosting Solutions — Complete Overview
**Your current setup:** Bare Git (Zurich) — SSH-only, no web UI, no issues
---
## SaaS Solutions (They Host, You Pay/Free)
### 1. GitHub (USA, Microsoft)
| | |
|--|--|
| **Type** | SaaS (Proprietary) |
| **Cost** | Free (public + private, 3 collaborators), Team $4/user/month |
| **Features** | Issues, PRs, Actions (CI/CD), Codespaces, Copilot |
| **Pros** | Everyone uses it, massive ecosystem, best integrations |
| **Cons** | US jurisdiction (CLOUD Act), vendor lock-in, Microsoft |
| **Best for** | OSS projects, when you need network effects |
---
### 2. GitLab.com (USA)
| | |
|--|--|
| **Type** | SaaS (Open Core — some features open, some proprietary) |
| **Cost** | Free (400 CI minutes/month), Premium $29/user/month |
| **Features** | Issues, MRs, CI/CD (built-in), Container registry, DevSecOps |
| **Pros** | Generous free CI, integrated DevOps platform |
| **Cons** | Complex, heavy, can be slow, US company |
| **Best for** | Teams wanting integrated CI/CD without setup |
---
### 3. Bitbucket (USA, Atlassian)
| | |
|--|--|
| **Type** | SaaS (Proprietary) |
| **Cost** | Free (5 users), Standard $3/user/month |
| **Features** | Issues, PRs, Pipelines (CI/CD), Jira integration |
| **Pros** | Works with Jira/Confluence if you use Atlassian |
| **Cons** | Smaller community than GitHub, Atlassian ecosystem lock-in |
| **Best for** | Teams already in Atlassian ecosystem |
---
### 4. SourceHut (USA, Drew DeVault)
| | |
|--|--|
| **Type** | SaaS (Open Source — sourcehut.org is open) |
| **Cost** | Free during beta, then ~$2/month or pay-what-you-want |
| **Features** | Git + Mercurial, email-based workflow, minimal web UI |
| **Pros** | No JavaScript, fast, privacy-focused, true open source |
| **Cons** | Different workflow (email-based), smaller community |
| **Best for** | Minimalists, people who hate web bloat |
---
### 5. Codeberg (Germany, EU)
| | |
|--|--|
| **Type** | SaaS (runs Gitea, non-profit) |
| **Cost** | Free (donations welcome) |
| **Features** | Gitea-based: Issues, PRs, CI via Woodpecker |
| **Pros** | EU-hosted (GDPR-friendly), non-profit, no tracking |
| **Cons** | Smaller than GitHub, occasional downtime |
| **Best for** | EU-based projects, privacy-conscious, avoiding Big Tech |
---
## Self-Hosted Solutions (You Host, You Control)
### 6. GitLab CE (Community Edition)
| | |
|--|--|
| **Type** | Open Core (CE is open, EE is proprietary) |
| **Cost** | Free (self-hosted) |
| **Install** | Complex — requires PostgreSQL, Redis, Ruby, Go |
| **Resources** | 4GB+ RAM minimum, prefers 8GB |
| **Features** | Issues, MRs, CI/CD (with runners), Registry, Wiki |
| **Pros** | Full-featured, industry standard for self-hosting |
| **Cons** | Heavy, complex to maintain, resource hungry |
| **Best for** | Large teams needing full DevOps platform |
---
### 7. Gitea (Go, Lightweight)
| | |
|--|--|
| **Type** | Open Source (MIT License) |
| **Cost** | Free |
| **Install** | 1 binary, 5 minutes |
| **Resources** | ~100MB RAM, runs on Raspberry Pi |
| **Features** | Issues, PRs, CI/CD (via Act runners), Registry, Wiki |
| **Pros** | Light, fast, easy, GitHub-like UI |
| **Cons** | Smaller ecosystem than GitLab, newer (less mature) |
| **Best for** | Small-medium teams, low resources, quick setup |
---
### 8. Gogs (Go, Minimal)
| | |
|--|--|
| **Type** | Open Source (MIT License) |
| **Cost** | Free |
| **Install** | 1 binary |
| **Resources** | Very light — lighter than Gitea |
| **Features** | Basic: repos, issues, PRs (simpler than Gitea) |
| **Pros** | Extremely light, simple |
| **Cons** | Less active development, fewer features than Gitea |
| **Best for** | Minimalists who just need repos + basic issues |
---
### 9. Forgejo (Gitea Fork)
| | |
|--|--|
| **Type** | Open Source (Fork of Gitea) |
| **Cost** | Free |
| **Origin** | Community fork after Gitea went to non-profit governance |
| **Features** | Same as Gitea |
| **Pros** | 100% community-controlled, no corporate influence |
| **Cons** | Newer fork, smaller community (for now) |
| **Best for** | Those who want Gitea features but pure community governance |
---
### 10. Your Current: Bare Git + SSH
| | |
|--|--|
| **Type** | Just Git (no platform) |
| **Cost** | Server cost only |
| **Install** | `git init --bare` |
| **Resources** | Minimal |
| **Features** | Git only — no issues, no PRs, no web UI |
| **Pros** | Full control, minimal attack surface, simple |
| **Cons** | No collaboration features, manual everything |
| **Best for** | Small teams, maximum control, minimal complexity |
---
## Summary: Which Should You Choose?
| Your Priority | Solution | Why |
|-------------|----------|-----|
| **Maximum visibility for OSS** | GitHub | Everyone's there |
| **EU data residency + OSS** | Codeberg | GDPR-friendly, non-profit |
| **Self-hosted, low resources** | Gitea | 1 binary, 100MB RAM |
| **Self-hosted, full DevOps** | GitLab CE | Complete platform |
| **Minimalist, email workflow** | SourceHut | No bloat, true open source |
| **Keep current + add issues** | Gitea on Zurich | Upgrade your bare Git |
| **Maximum control, no web** | Keep bare Git | What you have now |
---
## My Recommendation for You
**Hybrid: GitHub Free + Your Zurich Bare Git**
```
Public repo (clavitor) → GitHub Free (OSS visibility)
Private dev repo (clavitor-dev) → Zurich Bare Git (compliance/control)
```
**Or full upgrade:** Gitea on Zurich
- 1 binary install
- Web UI with issues/PRs
- Still self-hosted in Switzerland
- GDPR-friendly
**Want me to:**
- A) Write skill to install Gitea on Zurich?
- B) Set up GitHub Free + sync workflow?
- C) Keep current bare Git + document manual issue workflow?

153
scripts/daily-review.sh Executable file
View File

@ -0,0 +1,153 @@
#!/bin/bash
# Daily Review Script — Clavitor Agent Handbook Part 4
# Run this every morning before any new feature work.
# Any failure = foundation alert. Fix before proceeding.
set -e
FAILED=0
PASSED=0
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo "=== Clavitor Daily Review ==="
echo "Checking against CLAVITOR-AGENT-HANDBOOK.md Part 4"
echo ""
# Function to run a check
check() {
local name="$1"
local cmd="$2"
local expected="$3"
echo -n "Checking $name... "
if eval "$cmd" > /dev/null 2>&1; then
if [ "$expected" = "fail" ]; then
echo -e "${RED}❌ FAIL${NC} (should have failed but passed)"
FAILED=$((FAILED + 1))
else
echo -e "${GREEN}✅ PASS${NC}"
PASSED=$((PASSED + 1))
fi
else
if [ "$expected" = "fail" ]; then
echo -e "${GREEN}✅ PASS${NC} (correctly failed)"
PASSED=$((PASSED + 1))
else
echo -e "${RED}❌ FAIL${NC}"
FAILED=$((FAILED + 1))
fi
fi
}
echo "--- Section A: Server Hard Veto Checks ---"
# A1: Server never receives master_key
check "A1: No master_key on server" \
"grep -rn 'master_key\|MasterKey\|masterKey' clavis-vault/api/ clavis-vault/lib/ --include='*.go' | grep -v '_test.go' | head -1" \
"fail"
# A2: No DeriveP1 on server
check "A2: No DeriveP1 on server" \
"grep -rn 'DeriveP1\|derive_p1\|deriveP1' clavis-vault/lib/ clavis-vault/api/ | head -1" \
"fail"
# A3: No L2 credential functions
check "A3: No L2 credential functions" \
"grep -rn 'MintCredential\|ParseCredential\|CredentialToWire' clavis-vault/api/ clavis-vault/lib/ | head -1" \
"fail"
echo ""
echo "--- Section F: Test Posture ---"
# F1: Tests pass
echo -n "F1: Go tests pass... "
cd clavis/clavis-vault
if go test ./lib/... ./api/... > /tmp/test-output.log 2>&1; then
echo -e "${GREEN}✅ PASS${NC}"
PASSED=$((PASSED + 1))
else
echo -e "${RED}❌ FAIL${NC}"
echo " See: /tmp/test-output.log"
FAILED=$((FAILED + 1))
fi
cd ../..
# F2: Build succeeds
echo -n "F2: Build succeeds... "
cd clavis/clavis-vault
if go build -o /tmp/clavitor-test ./cmd/clavitor/ > /tmp/build-output.log 2>&1; then
echo -e "${GREEN}✅ PASS${NC}"
PASSED=$((PASSED + 1))
else
echo -e "${RED}❌ FAIL${NC}"
echo " See: /tmp/build-output.log"
FAILED=$((FAILED + 1))
fi
cd ../..
# F3: Check for test files (basic check)
echo -n "F3: Recent Go changes have tests... "
# Get files changed in last commit
CHANGED=$(git diff --name-only HEAD~1 2>/dev/null | grep '\.go$' | grep -v '_test.go' || true)
if [ -z "$CHANGED" ]; then
echo -e "${YELLOW}⚠️ SKIP${NC} (no Go changes in last commit)"
else
# Check each changed file has corresponding test
MISSING_TESTS=0
for f in $CHANGED; do
testfile="$(dirname $f)/$(basename $f .go)_test.go"
if [ ! -f "$testfile" ]; then
echo ""
echo -e " ${YELLOW}⚠️ WARNING: $f has no test file${NC}"
MISSING_TESTS=$((MISSING_TESTS + 1))
fi
done
if [ $MISSING_TESTS -eq 0 ]; then
echo -e "${GREEN}✅ PASS${NC}"
PASSED=$((PASSED + 1))
else
echo -e "${YELLOW}⚠️ PARTIAL${NC} ($MISSING_TESTS files without tests)"
fi
fi
echo ""
echo "--- Section G: Dead Code ---"
# G1: Empty directories
echo -n "G1: No empty directories... "
EMPTY=$(find . -type d -empty 2>/dev/null | grep -v ".git" | grep -v "vendor" | head -5)
if [ -z "$EMPTY" ]; then
echo -e "${GREEN}✅ PASS${NC}"
PASSED=$((PASSED + 1))
else
echo -e "${RED}❌ FAIL${NC}"
echo "$EMPTY" | while read dir; do
echo " $dir"
done
FAILED=$((FAILED + 1))
fi
# G2: No orphaned HTML (with exceptions)
echo -n "G2: No orphaned production files... "
# This is a simplified check - manual review still needed
ORPHANED=0
echo -e "${YELLOW}⚠️ MANUAL${NC} (see handbook for full G2 check)"
echo ""
echo "=== Summary ==="
echo -e "${GREEN}Passed: $PASSED${NC}"
if [ $FAILED -gt 0 ]; then
echo -e "${RED}Failed: $FAILED${NC}"
echo ""
echo -e "${RED}FOUNDATION ALERT: Fix failures before any new feature work.${NC}"
exit 1
else
echo -e "${GREEN}All checks passed. Ready for feature work.${NC}"
exit 0
fi