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:
parent
fd27a9d173
commit
b920203314
|
|
@ -1,6 +1,9 @@
|
|||
# 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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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.*
|
||||
|
|
@ -1,13 +1,10 @@
|
|||
# clavis-android
|
||||
|
||||
> **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** (晓).
|
||||
|
||||
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||
> **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.
|
||||
|
||||
## 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 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.
|
||||
|
||||
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.
|
||||
|
|
@ -1,14 +1,11 @@
|
|||
# clavis-chrome
|
||||
|
||||
> **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**.
|
||||
|
||||
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||
> **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.
|
||||
|
||||
## 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 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.
|
||||
- **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.
|
||||
|
|
@ -1,87 +1,55 @@
|
|||
# clavis-cli
|
||||
|
||||
> **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.
|
||||
|
||||
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||
> **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.
|
||||
|
||||
## Build
|
||||
|
||||
```
|
||||
make # build for host
|
||||
make strip # strip binary
|
||||
make clean # remove artifacts
|
||||
```
|
||||
|
||||
Target: `clavitor-cli` binary, <1MB stripped. Requires: C11 compiler, POSIX (Linux/macOS/FreeBSD/Windows).
|
||||
|
||||
## Architecture
|
||||
|
||||
- **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/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/util.c** — Base64 (standard + url-safe), URL encoding.
|
||||
|
||||
## Vendored dependencies
|
||||
|
||||
All in `vendor/`, no system package dependencies:
|
||||
- **BearSSL** — TLS, AES-GCM, HKDF, HMAC, PRNG
|
||||
- **QuickJS** — JS runtime for shared crypto logic
|
||||
- **cJSON** — JSON parsing
|
||||
|
||||
## Crypto design
|
||||
|
||||
Three-tier encryption model:
|
||||
- **L1** — first 8 bytes of L2 key, used as Bearer auth token
|
||||
- **L2** — 16-byte AES-128-GCM key, client-side field encryption/decryption
|
||||
- **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.
|
||||
|
||||
## 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-`.
|
||||
|
||||
## 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.
|
||||
|
||||
Endpoints used: `/api/entries`, `/api/search?q=`, `/api/entries/<id>`, `/api/ext/totp/<id>`.
|
||||
|
||||
## ⚒️ Foundation First — No Mediocrity. Ever.
|
||||
|
||||
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.
|
||||
|
||||
### 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 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.
|
||||
|
||||
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.
|
||||
|
||||
### 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.
|
||||
|
||||
The bar is high. The support is real.
|
||||
|
||||
## Testing
|
||||
|
||||
```
|
||||
./clavitor-cli test-crypto # BearSSL + JS crypto self-tests
|
||||
./clavitor-cli test-totp <seed> # TOTP generation from base32 seed
|
||||
./clavitor-cli test-roundtrip # runs crypto/test_crypto.js
|
||||
```
|
||||
```
|
||||
|
|
@ -1,18 +1,13 @@
|
|||
# clavis-crypto
|
||||
|
||||
> **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**.
|
||||
|
||||
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||
> **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.
|
||||
|
||||
## 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.
|
||||
- **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 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
|
||||
|
||||
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.
|
||||
|
|
@ -1,14 +1,11 @@
|
|||
# clavis-firefox
|
||||
|
||||
> **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**.
|
||||
|
||||
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||
> **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.
|
||||
|
||||
## 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 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.
|
||||
- **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.
|
||||
|
|
@ -1,13 +1,10 @@
|
|||
# clavis-ios
|
||||
|
||||
> **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** (晓).
|
||||
|
||||
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||
> **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.
|
||||
|
||||
## 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 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.
|
||||
|
||||
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.
|
||||
|
|
@ -1,15 +1,12 @@
|
|||
# clavis-safari
|
||||
|
||||
> **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**.
|
||||
|
||||
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||
> **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).
|
||||
|
||||
## 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 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.
|
||||
- **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.
|
||||
|
||||
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.
|
||||
|
|
@ -1,35 +1,23 @@
|
|||
# clavis-telemetry
|
||||
|
||||
> **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**.
|
||||
|
||||
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||
> **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.
|
||||
|
||||
## 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 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.
|
||||
- **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.
|
||||
|
||||
## Operations
|
||||
|
||||
### Log Retention
|
||||
|
||||
Tarpit logs contain scanner IPs for security analysis. Rotate/delete per your organization's retention policy (recommended: 30 days).
|
||||
|
||||
### External Alerting (Optional)
|
||||
|
||||
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_TOKEN` - Bearer token for authentication
|
||||
|
||||
If unset, outage logging continues without external notification.
|
||||
|
||||
### Kuma Monitoring (Optional)
|
||||
|
||||
Health push to Kuma can be configured via:
|
||||
- `KUMA_PUSH_URL` - Kuma push endpoint
|
||||
|
||||
If unset, Kuma push is disabled.
|
||||
If unset, Kuma push is disabled.
|
||||
|
|
@ -1,43 +1,25 @@
|
|||
# Clavis Vault — CLAUDE.md
|
||||
|
||||
> **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.
|
||||
|
||||
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||
> **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.
|
||||
|
||||
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.
|
||||
|
||||
### 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 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.
|
||||
|
||||
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.
|
||||
|
||||
### 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.
|
||||
|
||||
The bar is high. The support is real.
|
||||
|
||||
---
|
||||
|
||||
## Security Failures — NEVER HIDE THEM
|
||||
|
||||
**The cardinal rule:** If decryption/verification fails, expose the failure. Never fall back to plaintext. Never silently continue.
|
||||
|
||||
### WRONG — Silent fallback (fireable offense)
|
||||
```javascript
|
||||
try {
|
||||
|
|
@ -46,7 +28,6 @@ try {
|
|||
decrypted = plaintext; // NEVER DO THIS
|
||||
}
|
||||
```
|
||||
|
||||
### CORRECT — Visible failure
|
||||
```javascript
|
||||
try {
|
||||
|
|
@ -55,24 +36,17 @@ try {
|
|||
decrypted = '[decryption failed]'; // User sees the failure
|
||||
}
|
||||
```
|
||||
|
||||
This applies to:
|
||||
- Encryption/decryption errors
|
||||
- Signature verification failures
|
||||
- Authentication failures
|
||||
- Tampering detection
|
||||
- Any security-critical operation
|
||||
|
||||
**Security failures must be noisy, visible, and blocking — never silent, hidden, or permissive.**
|
||||
|
||||
See `SECURITY.md` for full principles.
|
||||
|
||||
---
|
||||
|
||||
## Edition System (Community vs Commercial)
|
||||
|
||||
Clavitor Vault has two editions with build-time separation:
|
||||
|
||||
### Community Edition (Default)
|
||||
```bash
|
||||
go build -o clavitor ./cmd/clavitor/
|
||||
|
|
@ -81,7 +55,6 @@ go build -o clavitor ./cmd/clavitor/
|
|||
- Local logging only
|
||||
- Self-hosted
|
||||
- Elastic License 2.0
|
||||
|
||||
### Commercial Edition
|
||||
```bash
|
||||
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`
|
||||
- Multi-POP management
|
||||
- Commercial license
|
||||
|
||||
### Using the Edition Package
|
||||
|
||||
```go
|
||||
import "github.com/johanj/clavitor/edition"
|
||||
|
||||
// Send operator alerts (works in both editions)
|
||||
edition.Current.AlertOperator(ctx, "auth_error", "message", details)
|
||||
|
||||
// Check edition
|
||||
currentEdition := edition.Current.Name() // "community" or "commercial"
|
||||
```
|
||||
|
||||
See `edition/CLAUDE.md` for full documentation.
|
||||
|
||||
---
|
||||
|
||||
## Clavitor Vault v2 — Current State & Testing
|
||||
|
||||
### What we built this session
|
||||
|
||||
#### 1. Domain classification for import scopes
|
||||
- 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`
|
||||
|
|
@ -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 are sent in chunks of 200 to stay within token limits
|
||||
- Classification is opt-in: user sees consent dialog with Yes/Skip/Cancel
|
||||
|
||||
#### 2. Import flow UX
|
||||
- Drop file → parse → hide file step → consent dialog (Yes/Skip/Cancel)
|
||||
- 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
|
||||
- Global black checkboxes (`accent-color: var(--text)`)
|
||||
- Unified CSS classes: `.item-row`, `.item-icon`, `.item-list` (replacing import-specific classes)
|
||||
|
||||
#### 3. Import filtering visibility (NEW)
|
||||
- Import parsers now track what gets filtered and why
|
||||
- `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"`
|
||||
- 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.
|
||||
|
||||
#### 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.
|
||||
- **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)
|
||||
- **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.
|
||||
|
||||
#### 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.
|
||||
- **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 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.
|
||||
|
||||
### 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:
|
||||
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
### 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:
|
||||
- Requires a stolen agent token (already a compromise)
|
||||
- Requires racing first contact from two different IPs
|
||||
- The "loser" simply won't be auto-whitelisted
|
||||
- Cannot be reproduced in testing; practically impossible to trigger
|
||||
- Fix would require plaintext column + atomic update (not worth complexity)
|
||||
|
||||
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.
|
||||
|
||||
This was reviewed and accepted because:
|
||||
- 5-10 minute token lifetime makes re-auth acceptable
|
||||
- It's a UX inconvenience, not a security vulnerability
|
||||
- Deferring consumption until operation success would require transaction-like complexity
|
||||
- Rare edge case: requires admin operation to fail after token validation
|
||||
|
||||
### How testing works
|
||||
|
||||
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/
|
||||
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).
|
||||
|
|
@ -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.
|
||||
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).
|
||||
|
||||
### Key files
|
||||
|
||||
| File | What |
|
||||
|------|------|
|
||||
| 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/clavitor-app.css | All styles, item-row/item-icon system |
|
||||
| clavitor.ai/main.go | Portal + /classify endpoint (Haiku on OpenRouter) |
|
||||
|
||||
### Deploy Clavitor Vault (dev)
|
||||
|
||||
Working directory: `/home/johan/dev/clavitor/clavis/clavis-vault`
|
||||
|
||||
**Prerequisites:**
|
||||
```bash
|
||||
# Enable user systemd services (one-time setup)
|
||||
systemctl --user enable --now clavitor.service
|
||||
```
|
||||
|
||||
**Build and deploy (one command):**
|
||||
```bash
|
||||
make dev # stop → build → start (graceful shutdown via SIGTERM)
|
||||
```
|
||||
|
||||
**Individual commands:**
|
||||
```bash
|
||||
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 build # go build...
|
||||
```
|
||||
|
||||
**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).
|
||||
|
||||
**Update Caddy config:**
|
||||
```bash
|
||||
ssh root@192.168.0.2
|
||||
# Edit /etc/caddy/Caddyfile, then:
|
||||
systemctl reload caddy
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
### Deploy clavitor.ai (prod)
|
||||
|
||||
Working directory: `/home/johan/dev/clavitor/clavitor.ai`
|
||||
|
||||
```bash
|
||||
make deploy-prod
|
||||
```
|
||||
|
||||
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).
|
||||
|
||||
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.**
|
||||
|
||||
Verify: `ssh root@<tailscale-ip> "systemctl status clavitor-web"`
|
||||
|
||||
### 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.**
|
||||
|
|
@ -1,26 +1,19 @@
|
|||
# Clavitor Website — clavitor.com
|
||||
|
||||
> **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**.
|
||||
|
||||
> **Quickstart (60s):** [../QUICKSTART.md](../QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||
> **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.
|
||||
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.
|
||||
|
||||
**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 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.
|
||||
- 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.
|
||||
|
||||
**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.
|
||||
|
||||
The bar is high. The support is real. These rules apply to you now.
|
||||
|
||||
## Architecture
|
||||
- Go web server (`main.go`) with `go:embed` for templates, CSS, SVGs, PNGs
|
||||
- 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`)
|
||||
- Port 8099
|
||||
- License: Elastic License 2.0 (NOT MIT)
|
||||
|
||||
## Deployment
|
||||
|
||||
### Dev (forge = 192.168.1.16, Florida — dev.clavitor.ai)
|
||||
```
|
||||
make dev # build + restart locally
|
||||
make deploy-dev # same thing
|
||||
```
|
||||
Dev runs on forge (localhost). `dev.clavitor.ai` DNS points to home IP.
|
||||
|
||||
### Prod (Zürich — clavitor.ai — clavitor.ai)
|
||||
```
|
||||
make deploy-prod # cross-compile amd64, scp to Zürich, restart systemd
|
||||
```
|
||||
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`.
|
||||
|
||||
### First-time setup (already done)
|
||||
```
|
||||
make setup-prod # creates /opt/clavitor-web, systemd service, uploads binary+db
|
||||
```
|
||||
Then manually update `/etc/caddy/Caddyfile` to reverse_proxy.
|
||||
|
||||
### SSH
|
||||
- Prod: `ssh root@clavitor.ai`
|
||||
- Tailscale: `zurich` (100.70.148.118) — SSH may be blocked via Tailscale
|
||||
|
||||
## Build & Run
|
||||
```
|
||||
CGO_ENABLED=1 go build -o clavitor-web .
|
||||
./clavitor-web
|
||||
```
|
||||
CSS and SVG changes require rebuild (embedded at compile time). Template changes reload in dev mode.
|
||||
|
||||
## Brand & Design
|
||||
- Light mode only. Single source of truth: `clavitor.css`
|
||||
- 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)
|
||||
- No inline styles, no CSS in templates. Everything in clavitor.css.
|
||||
- Always capitalize "Clavitor" in prose. Lowercase in code/paths/commands.
|
||||
|
||||
## Encryption Terminology
|
||||
- **Vault Encryption** — whole vault at rest
|
||||
- **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)
|
||||
- Never use "sealed fields", "agent fields", "L1", "L2", "L3"
|
||||
- Agents use CLI, NOT MCP (MCP exposes plaintext; CLI is scoped)
|
||||
|
||||
## POPs (Points of Presence)
|
||||
- Stored in `pops` table in clavitor.db — the single source of truth
|
||||
- Map on /hosted is generated dynamically from DB via JavaScript
|
||||
- Zürich = HQ, black dot, larger (11×11). Live POPs = red. Planned = light red.
|
||||
- "You" visitor dot = circle (not square — "you" is not clavitor)
|
||||
|
||||
## Key URLs
|
||||
- `/hosted` — hosted product page with dynamic world map
|
||||
- `/glass` — looking glass (latency from user's browser)
|
||||
- `/noc?pin=250365` — NOC dashboard (telemetry, read-only, hardcoded PIN)
|
||||
- `/telemetry` — POST endpoint for POP agent heartbeats (no auth)
|
||||
- `/ping` — server-side TCP ping (for diagnostics)
|
||||
|
||||
## Vault Binary
|
||||
- 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`
|
||||
|
|
@ -99,10 +81,9 @@ CSS and SVG changes require rebuild (embedded at compile time). Template changes
|
|||
- Vault runs on port 1984 with TLS
|
||||
- Has `/ping` endpoint (11 bytes, no DB, CORS via middleware) for looking glass
|
||||
- Has `/health` endpoint (heavier, queries DB)
|
||||
|
||||
## Providers
|
||||
- AWS: most POPs (free tier t4g.micro)
|
||||
- LightNode: Santiago, Bogotá, Manila, Dhaka
|
||||
- ishosting: Istanbul, Almaty
|
||||
- HostAfrica: Lagos, Nairobi
|
||||
- Rackmill: Perth
|
||||
- Rackmill: Perth
|
||||
|
|
@ -1,25 +1,19 @@
|
|||
# clavitor.ai/admin — central admin / Paddle integration
|
||||
|
||||
> **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**.
|
||||
|
||||
> **Quickstart (60s):** [../QUICKSTART.md](../QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||
> **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.
|
||||
|
||||
## 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 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 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.
|
||||
|
||||
## Vault slot lifecycle (canonical)
|
||||
|
||||
Pre-create at subscription time:
|
||||
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.
|
||||
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.
|
||||
|
||||
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.
|
||||
|
|
@ -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?
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue