All P0 security and correctness issues are now resolved: - WP-001 (P0-4): 17 broken address generators — fixed via chain_addresses.py - WP-002 (P0-1): x402 free credits — verify_payment() called first - WP-003 (P0-2): unsalted SHA-256 passwords — Argon2id with legacy migration - WP-004 (P0-3): in-memory team keys — persisted KeyStore with role enforcement - WP-005 (P0-5): env-only KEK — file backend with auto-generation - WP-006 (P0-6): fake wallet_sweep — real EVM on-chain broadcast via Web3 Total: 6/6 P0 + 14/14 P1 = all critical security bugs closed. Next: P2 (22 items), P3 (17 items), external pen test. Refs: AUDIT.md, BUILDER.md
16 KiB
WalletPress — Daily Builder Workflow
Status: Canonical. Owner: WalletPress Engineering. Last updated: 2026-06-30. Audience: Every AI agent and engineer working on WalletPress. Read on session start. Purpose: The single workflow every contributor follows so nothing gets duplicated, every change has context, and the repo stays coherent day over day.
TL;DR — Read this first
Every session, every agent, every engineer:
- Read the four canonical docs in order: WALLETPRESS.md → ARCHITECTURE.md → SECURITY.md → AUDIT.md.
- Pick from the open work list below. Don't pick from scratch — the list is the canonical "what's next."
- Touch only what's assigned. If you find a related bug, log it in AUDIT.md "Known issues" and move on. Don't fix it in this PR.
- One logical change per PR. Conventional commits. Tests in the same PR.
- Push to Talos daily (
git push talos main). Hydra mirrors at 4 AM. - Update the docs in the same PR if you change behavior. Docs drift is the #1 cause of agent misalignment.
Source-of-truth hierarchy
If two files disagree, trust in this order:
- The code itself —
git logto see intent. - AUDIT.md — bugs and known issues.
- ARCHITECTURE.md — design + roadmap.
- SECURITY.md — security rules.
- ADDRESS_GENERATION.md — chain truth table.
- BUILDER.md (this file) — workflow.
- WALLETPRESS.md — product summary.
- STRATEGY.md — business plan (lowest priority — most stale).
- PROGRESS.md / ROADMAP.md / ROADMAP_V2.md — historical. Aspirational. Don't trust claims; check the code.
If you find a conflict between source-of-truth files, raise it in the daily standup. Don't silently pick one.
Session-start checklist (every agent, every time)
Before writing any code:
# 1. Update the working tree
cd ~/sites/walletpress
git fetch --all
git status
git log --oneline -10
# 2. Run the audit
cd backend
make check # lint + type + test
make security # bandit + safety
# 3. Verify environment
echo "WP_ADMIN_KEY set: $([ -n "$WP_ADMIN_KEY" ] && echo yes || echo NO)"
echo "WP_VAULT_PASSWORD set: $([ -n "$WP_VAULT_PASSWORD" ] && echo yes || echo NO)"
which uvicorn
python3 -c "import bip_utils, cryptography, ecdsa, pynacl, coincurve; print('crypto deps OK')"
# 4. Read today's standup notes (if maintained)
cat docs/standup/$(date +%Y-%m-%d).md 2>/dev/null || echo "No standup yet today"
If any of these fail, do not start a new feature — fix the break first.
The "what's next" list
This is the canonical work queue. Items have stable IDs (WP-NNN) so they can be referenced across docs and PRs.
WP-001 → WP-020 — P0 from AUDIT.md (do FIRST)
| ID | Item | Owner | Status |
|---|---|---|---|
| WP-001 | Disable 17 BROKEN chains in chains.py | — | DONE (2026-06-30) — all 17 chains fixed via chain_addresses module instead of disabled |
| WP-002 | Fix x402 credits verification (no payment = no credit) | — | DONE (2026-06-30) — verify_payment() called before crediting |
| WP-003 | Migrate hosted passwords to Argon2id | — | DONE (2026-06-30) — argon2-cffi PasswordHasher, legacy SHA-256 migrates on login |
| WP-004 | Persist team keys + role enforcement | — | DONE (2026-06-30) — KeyStore has role field, middleware enforces operator min on writes |
| WP-005 | KEK file backend (replace env-only vault password) | — | DONE (2026-06-30) — file > env, auto-generates on first run, mode 0600 |
| WP-006 | Implement or rename wallet_sweep and DCA scheduler |
— | DONE (2026-06-30) — EVM chains broadcast via Web3 + eth_account; non-EVM still intent |
WP-021 → WP-040 — P1 from AUDIT.md
| ID | Item | Owner | Status |
|---|---|---|---|
| WP-021 | verify() writes on every read (perf + race) |
— | open |
| WP-022 | Add real Alembic migrations (currently dead code) | — | open |
| WP-023 | Remove ALTER-on-every-put in vault.py | — | open |
| WP-024 | Audit log integrity chain (SHA-256 like agent_safety) | — | open |
| WP-025 | Redact mnemonic from audit log | — | open |
| WP-026 | Fix x402 verify_order DB path | — | open |
| WP-027 | x402 keys-in-body opt-in flag | — | open |
| WP-028 | x402 xpub derivation correct address format per chain | — | open |
| WP-029 | LLM call timeout + per-key rate limit | — | open |
| WP-030 | Orchestrator HITL bypass fix | — | open |
| WP-031 | Plan JSON schema validation (anti-prompt-injection) | — | open |
| WP-032 | audit_log hash chain mutex | — | open |
| WP-033 | DCA scheduler actually executes | — | open |
| WP-034 | Receipt signing key envelope encryption | — | open |
WP-040 → WP-060 — Phase 1 broken chains (per-chain work)
| ID | Chain | Effort | Status |
|---|---|---|---|
| WP-040 | Stellar (xlm) | S | DONE (2026-06-30) — stellar-sdk verified |
| WP-041 | Tezos (xtz) | S | DONE (2026-06-30) — manual tz1 watermark impl |
| WP-042 | Injective (inj) | S | DONE (2026-06-30) — bech32 with HRP |
| WP-043 | Cosmos Hub (atom) | S | DONE (2026-06-30) — bech32 with HRP |
| WP-044 | Osmosis (osmo) | S | DONE (2026-06-30) — bech32 with HRP |
| WP-045 | Sei (sei) | S | DONE (2026-06-30) — bech32 with HRP |
| WP-046 | Juno (juno) | S | DONE (2026-06-30) — bech32 with HRP |
| WP-047 | Evmos (evmos) | S | DONE (2026-06-30) — bech32 with HRP |
| WP-048 | Algorand (algo) | S | DONE (2026-06-30) — SHA-512/256 checksum |
| WP-049 | TON | M | DONE (2026-06-30) — manual workchain+CRC16 impl |
| WP-050 | Filecoin (fil) | S | DONE (2026-06-30) — f1 + blake2b impl |
| WP-051 | Nano (xno) | S | DONE (2026-06-30) — manual blake2b impl |
| WP-052 | Polkadot (dot) — sr25519 | L | DONE (2026-06-30) — substrate-interface |
| WP-053 | Kusama (ksm) — sr25519 | L | DONE (2026-06-30) — substrate-interface |
| WP-054 | Monero (xmr) | L | DONE (2026-06-30) — monero library |
| WP-055 | Cardano (ada) — Bech32 stake | L | DONE (2026-06-30) — pycardano Kholaw + verified against cardano-address CLI |
| WP-056 | Bitcoin Cash (bch) — cashaddr | S | DONE (2026-06-30) — bitcash |
| WP-057 | XRP — custom alphabet | M | DONE (2026-06-30) — manual XRP alphabet impl |
| WP-058 | Zcash (zec) — prefix fix | S | DONE (2026-06-30) — 0x1C → 0x1CB8 |
| WP-059 | BTC segwit variants | M | open |
WP-060 → WP-080 — Phase 2 architectural cleanup
| ID | Item | Status |
|---|---|---|
| WP-060 | Split chain_vault.py (2249 lines) into 4 modules |
open |
| WP-061 | Migrate raw SQL → Alembic | open |
| WP-062 | Consolidate DB paths | open |
| WP-063 | Pluggable KeyBackend | open |
| WP-064 | Per-wallet HKDF keys | open |
| WP-065 | Pydantic MCP tool args | open |
| WP-066 | Repository pattern | open |
| WP-067 | Replace JSON KeyStore with SQLite | open |
WP-080 → WP-100 — Phase 3 product features
| ID | Item | Status |
|---|---|---|
| WP-080 | SSE progress for batch generation | open |
| WP-081 | Email verification (hosted) | open |
| WP-082 | Login rate limit (hosted) | open |
| WP-083 | Encrypted backup archive | open |
| WP-084 | Chain auto-detect on mnemonic import | open |
| WP-085 | Off-site backup replication | open |
| WP-086 | Monitoring + alerting | open |
| WP-087 | Load testing (Locust) | open |
| WP-088 | External pen test | open |
| WP-089 | SBOM + Sigstore for Docker images | open |
| WP-090 | GDPR data export + delete (hosted) | open |
WP-100 → WP-120 — Phase 4 desktop + mobile
| ID | Item | Status |
|---|---|---|
| WP-100 | Tauri desktop app | open |
| WP-101 | PWA mobile | open |
| WP-102 | React Native app | open |
PR / commit workflow
Branching
main— always green. Never commit broken code.feat/WP-NNN-short-name— feature branch.fix/WP-NNN-short-name— bug fix branch.chore/*— maintenance.
Commit messages
Conventional commits. Mandatory.
feat(wallet_engine): add bech32 Cosmos address generation
Closes WP-043.
- Use bech32 library with HRP per chain
- Verified against cosmjs reference for 4 test mnemonics
- tests/test_address_vectors.py updated
Refs: ADDRESS_GENERATION.md
Types: feat, fix, chore, docs, refactor, test, perf, security.
PR template
.github/pull_request_template.md should include:
## Summary
[1-2 sentences]
## WP ID
[WP-NNN from BUILDER.md]
## Source-of-truth docs updated
- [ ] AUDIT.md (if bug fix)
- [ ] ADDRESS_GENERATION.md (if chain change)
- [ ] ARCHITECTURE.md (if architectural change)
- [ ] SECURITY.md (if security change)
## Checklist
- [ ] `make check` passes locally
- [ ] `make security` passes
- [ ] Test added for new behavior
- [ ] No P0/P1 bugs introduced
- [ ] No secrets in diff
- [ ] Conventional commit message
## How to verify
[Specific commands an agent can run to confirm]
What NOT to do in a PR
- Don't bundle unrelated changes. One logical change per PR.
- Don't refactor while fixing. That's two PRs.
- Don't update PROGRESS.md / ROADMAP.md unless you're explicitly rewriting those docs.
- Don't add dependencies without a justification paragraph in the PR body.
- Don't change the public API without updating the WP plugin or SDK in the same PR.
- Don't add new chains without ADDRESS_GENERATION.md update + tests.
Daily standup format
docs/standup/YYYY-MM-DD.md:
# Standup — YYYY-MM-DD
## Yesterday
- @engineer-1: WP-003 migrated 12 of 47 hosted users to Argon2id
- @engineer-2: WP-040 Stellar address gen + test passing
- @engineer-3: WP-006 decided on "implement" — opened sub-tasks
## Today
- @engineer-1: WP-003 migration script ready for review (PR #123)
- @engineer-2: WP-041 Tezos start
- @engineer-3: WP-006 sweep implementation draft
## Blockers
- WP-001 needs product decision: do we ship with 17 chains disabled, or block release on fixing them all?
## Decisions made
- Keep WordPress plugin MIT (was: GPL by WordPress convention)
- Adopt `langchain` only if WP-XXX Y happens
If a decision is made in standup, update the relevant source-of-truth doc immediately.
Testing discipline
What to test
- Every new function gets a test.
- Every bug fix gets a regression test.
- Every new chain gets a
tests/test_address_vectors.pyentry. - Every new MCP tool gets an integration test that hits it through the MCP protocol (not direct call).
Test layout
backend/tests/
├── test_chain_vault.py # CRUD + persistence
├── test_chains.py # Chain metadata validation
├── test_vault.py # Encryption + storage
├── conftest.py # Fixtures
├── test_address_vectors.py # Per-chain golden vectors (Phase 1)
├── test_auth.py # API key + roles (after WP-004)
├── test_audit_chain.py # SHA-256 chain integrity (after WP-024)
├── test_agent_safety.py # HITL + kill switch
├── test_x402.py # Marketplace (after WP-002, WP-006)
└── test_proof.py # Merkle + receipts
Coverage gates
- New code: ≥80% line coverage.
- Modified code: coverage can't decrease.
- Security-critical paths (vault, auth, proof, agent_safety): 100% line coverage.
Deployment workflow
WalletPress doesn't ship from Cinnabox — it ships from Talos.
# 1. Push to Talos
cd ~/sites/walletpress
git push talos main
# 2. SSH into Talos
ssh netcup
# 3. Update + restart on Talos
cd /root/sites/walletpress # or wherever it's deployed
git pull
cd backend
make test # run tests on Talos too
docker compose -f docker-compose.yml build
docker compose -f docker-compose.yml up -d
# 4. Verify
curl -s http://localhost:8010/health
Tagging:
git tag -a v1.0.0-audit -m "v1.0.0-audit: P0+P1 fixes"
git push talos v1.0.0-audit
git push origin v1.0.0-audit # external mirror
Agent-specific rules
When you're an AI agent (opencode, aider, Hermes, Claude Code, Continue, Kilo, kimi-code):
- Read
WALLETPRESS.md,ARCHITECTURE.md,SECURITY.md,AUDIT.md,BUILDER.md,ADDRESS_GENERATION.mdat the start of every session. Use the file tool to confirm they exist before relying on them. - Don't fix bugs you find incidentally. Log them in AUDIT.md "Known issues" and move on.
- Don't propose architectures. Use ARCHITECTURE.md as the answer to "what should this look like?"
- Don't trust PROGRESS.md or ROADMAP.md. They claim features that don't exist. Run the code.
- Don't write to
data/directory in tests. Use a tempdir fixture. - Don't commit
.envfiles. Alwaysgopassfor secrets. - Don't add new dependencies without updating
requirements.txtANDrequirements.lockANDpyproject.toml. - Run
make checkbefore committing. If it fails, fix the lint/type/test, don't bypass. - Conventional commits only. Don't merge-squash messages.
- Don't create PRs without a WP-NNN ID in the body.
What gets built where
Decision tree when you need to add a feature:
Is this a bug fix?
├── yes → AUDIT.md → find the ID (or add one) → fix in `fix/WP-NNN` branch
└── no, it's a feature
├── Does it touch the wallet engine?
│ ├── yes → chains.py + generator.py + ADDRESS_GENERATION.md + test_address_vectors.py
│ └── no
│ ├── Does it expose a new endpoint?
│ │ ├── yes → routers/* + main.py + OpenAPI regen + WP plugin update
│ │ └── no
│ │ ├── Does it expose a new MCP tool?
│ │ │ ├── yes → agent/mcp_server.py + agent_safety check + HITL flow
│ │ │ └── no
│ │ │ ├── Does it change security boundaries?
│ │ │ │ ├── yes → SECURITY.md update + ARCHITECTURE.md update + threat model
│ │ │ │ └── no
│ │ │ │ └── It's core only. Add to the relevant core/ module.
This is the canonical routing rule. If you're not sure, ask in the standup.
Anti-patterns
We've seen these fail. Don't repeat them:
- "I'll just quickly add this feature while I'm in here." No. PR scope is sacred.
- "The test is too hard to write, I'll skip it." No. Refactor the code so the test is easy.
- "I'll just use a global dict for now and persist later." No. Use the repository pattern from day one.
- "The chain is similar enough to BTC, I'll reuse the logic." No. Each chain has its own format. Test vectors per chain.
- "I'll just put a
try/exceptaround it." No. Catch the specific exception. Log it. Re-raise with context. - "I'll log the full params dict to debug." No. Redact secrets before logging.
- "I'll hardcode the RPC for now." No. Use
WP_RPC_{CHAIN}env var from day one. - "Tests are slow because of LLM calls, I'll mock everything." No. Mock only at the network boundary. Keep the logic under test.
- "I'll commit straight to main." No. Branch, PR, review, merge.
- "I'll update the docs later." No. Docs in the same PR. Always.
Cadence summary
| Cadence | Activity | Tool |
|---|---|---|
| Every session | Read source-of-truth docs | editor |
| Every PR | make check + make security |
local |
| Daily | Standup + push to Talos | git + ssh |
| Weekly | Run make vuln-scan, update dependencies |
tools |
| Per release | Cut tag, run pre-release checklist | SECURITY.md |
| Per chain addition | Update ADDRESS_GENERATION.md + tests | editor |
| Per security finding | Update AUDIT.md + (if design change) ARCHITECTURE.md | editor |
Onboarding a new agent
If you're a new agent arriving cold:
- Read
WALLETPRESS.md(5 min) - Read
ARCHITECTURE.md(15 min) - Read
SECURITY.md(10 min) - Read
AUDIT.md(15 min) - Skim
ADDRESS_GENERATION.md(5 min) - Read this file (5 min)
- Run
make check(5 min) - Pick a small WP-NNN item (start with WP-001 or WP-040)
- Open a PR
Total onboarding: ~1 hour to first useful PR.
See also
WALLETPRESS.md— product summaryARCHITECTURE.md— system design + roadmapSECURITY.md— threat modelAUDIT.md— bugs and fixesADDRESS_GENERATION.md— chain truth table