Conversation history database-as-a-service for AI agents.
packages/
api/ Hono API on Cloudflare Workers + D1
shared/ Shared TypeScript types (public API contract)
dashboard/ Astro + React islands + Clerk + Tailwind v4 (served as static assets by API Worker)
docs/ Integration guides
scripts/ Setup and deployment scripts
See docs/knowledge/core-memory.md for durable maintenance notes. Do not create dated AI review reports; fold recurring findings into core memory and keep docs/INDEX.md updated.
For automation runs, read $CODEX_HOME/automations/code-smell-detector/memory.md before scanning commits. In sandboxed checkouts, use the writable Bun/Wrangler paths recorded in docs/knowledge/core-memory.md if verification commands hit tempdir or Wrangler log permission errors. Dashboard preview and production workflows should keep using bun install from the repo root unless the repo later adds a real pnpm-lock.yaml workspace.
Architecture: Single Cloudflare Worker serves both the REST API (/api/v1/*) and dashboard static assets.
# Install
bun install
# Local dev — API (port 8787)
cd packages/api
bunx wrangler dev
# Local dev — Dashboard (port 4321, separate dev server)
cd packages/dashboard
bun run dev
# Dashboard production build (CI/Pages)
cd packages/dashboard
PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_placeholder bun run build
# Sandboxed runs
export BUN_TMPDIR=/private/tmp/codex-bun-tmp BUN_INSTALL_CACHE_DIR=/private/tmp/codex-bun-cache XDG_CONFIG_HOME=/private/tmp/codex-wrangler-config
# Prefix `bunx tsc`, `bunx vitest`, and Wrangler commands with the env block above when the sandbox blocks default temp or config paths.
# Database
bunx drizzle-kit generate # Generate migrations
bunx wrangler d1 migrations apply agentstate-db --local # Apply locally
bunx wrangler d1 execute agentstate-db --local --file=scripts/seed.sql # Seed
# Lint + Format
bunx biome check packages/api/src/ # Check
bunx biome check --write packages/api/src/ # Auto-fix
# Type check
bunx tsc --noEmit -p packages/api/tsconfig.json
# Test
cd packages/api && bunx vitest run
# Deploy
cd packages/api
WRANGLER_DEPLOY_CONFIG=wrangler.deploy.jsonc bash scripts/prepare-wrangler-deploy-config.sh
npx wrangler deploy -c wrangler.deploy.jsonc
# Shortcut: `bun run deploy` from the repo root delegates to the API deploy script above.- Package manager: Bun
- Linter/Formatter: Biome
- API Framework: Hono (ultrafast, Workers-native)
- ORM: Drizzle ORM (type-safe, D1/SQLite)
- Database: Cloudflare D1 (SQLite at edge)
- Auth (API): Bearer token with SHA-256 hashed API keys
- Auth (Dashboard): Clerk (client-side keyless mode for dev; prod keys in
.env.production) - AI: Workers AI for title generation and follow-up questions
- Deployment: Single Cloudflare Worker serves both API and dashboard static assets
- IDs: nanoid (21 chars), auto-generated via Drizzle
$defaultFn - Timestamps: Unix milliseconds (Date.now()), stored as INTEGER in SQLite
- API responses: snake_case field names
- API keys: Format
as_live_+ 40 base62 chars. Only SHA-256 hash stored. - Metadata: JSON serialized as TEXT column, parsed on read
- Pagination: Cursor-based (never offset-based)
- Error format:
{ error: { code: "MACHINE_CODE", message: "Human message" } }
packages/api/src/db/schema.ts— Single source of truth for DB schemapackages/api/src/middleware/auth.ts— API key auth (critical security path)packages/api/src/routes/conversations/— Core CRUD operationspackages/api/src/routes/projects.ts— Project and key management routespackages/api/drizzle/— Generated SQL migrations (committed to git). If you hand-write a.sqlmigration (bypassingbunx drizzle-kit generate), you MUST also add its entry todrizzle/meta/_journal.jsonin the same PR (in wrangler apply order, i.e. filename order) — otherwise the nextdrizzle-kit generatediffs against a stale baseline and emits broken migrations (see #292).
# Run all tests
cd packages/api && bunx vitest run
# Local test API key (from seed.sql):
as_live_TEST_KEY_FOR_LOCAL_DEV_ONLY_1234567890ab
# Health check
curl http://localhost:8787/
# Create conversation
curl -X POST http://localhost:8787/v1/conversations \
-H "Authorization: Bearer as_live_TEST_KEY_FOR_LOCAL_DEV_ONLY_1234567890ab" \
-H "Content-Type: application/json" \
-d '{"messages":[{"role":"user","content":"Hello"}]}'- Semantic commits:
feat:,fix:,chore:,docs:,refactor:,test: - Co-authors (always include both):
Co-Authored-By: Duyet Le <me@duyet.net>
Co-Authored-By: duyetbot <bot@duyet.net>
See PLAN.md for the full maintenance playbook, quality benchmarks, scenario tables, and backlog. Keep PLAN.md up to date after every iteration.
When the cron fires, run this full cycle:
Run all quality checks in parallel. If any regress, fix before proceeding.
bunx biome check packages/api/src/
bunx tsc --noEmit -p packages/api/tsconfig.json
cd packages/api && bunx vitest run
cd packages/sdk && bun run typecheck && bun run build && bun run test
cd packages/python-sdk && python -m pytest -q
bun run test:sdk-examples
cd packages/dashboard && bun install && bun run build
git status --short- Read current state: Check PLAN.md backlog, memory files, recent git log
- Brainstorm: What has the biggest impact right now?
- Next unchecked backlog item ready to build
- Quality gaps (test coverage, type safety, accessibility)
- Architectural improvements that unlock future work
- Dashboard UX gaps users would expect
- Developer experience — docs accuracy, SDK completeness
- Plan: For non-trivial items, use Agent (Plan) to design approach. Write plan to memory if it spans multiple iterations.
- Prioritize: Pick 2-4 concrete tasks for parallel execution without file conflicts. Prefer high-impact items.
Spawn 2-4 parallel agents in a single message (run_in_background: true):
- Use PLAN.md scenario tables as menu
- Mix categories: feature + quality + dashboard + docs
- Agents touch different files — no conflicts
- senior-engineer for features/refactors, junior-engineer for lint/format/dead-code, code-reviewer for audits
- Review agent outputs — reject anything that breaks existing behavior
- Full quality suite: lint → typecheck → test
- If anything fails, fix before continuing
- Create feature branch:
git checkout -b claude/improvement-<timestamp> - Commit each logical change separately with semantic messages + co-authors
- Push branch and create PR:
gh pr create --title "..." --body "..." - Monitor CI: poll
gh pr checks <pr-number>until all checks pass or fail - If CI passes → merge:
gh pr merge <pr-number> --squash --delete-branch - If CI fails → fix issues, push again, re-check
- After merge → deploy:
cd packages/api && WRANGLER_DEPLOY_CONFIG=wrangler.deploy.jsonc bash scripts/prepare-wrangler-deploy-config.sh && npx wrangler deploy -c wrangler.deploy.jsonc - Verify:
curl -s -o /dev/null -w '%{http_code}' https://agentstate.app/api - Update memory benchmark scores + PLAN.md
- What was accomplished?
- What should the NEXT iteration focus on?
- Any blockers or decisions needing user input?
- Save insights to memory for continuity
- Always use PR workflow — never push directly to main
- One commit per logical change
- Skip iteration if working tree is dirty from user work
- Save progress to memory after each run
- Don't repeat work from previous iterations — check memory first
- If a brainstormed idea is too large, break into phases and save plan to memory
# 1. Fill in credentials
cp .env.example .env.local
# Edit .env.local with your Cloudflare credentials
# 2. Set GitHub secrets
./scripts/setup-secrets.sh
# 3. Create D1 database
bunx wrangler d1 create agentstate-db
# Update database_id in packages/api/wrangler.jsonc
# 4. Push to main → auto-deploys via GitHub Actions
git push origin main