Backend:
- Add before_seq + limit params to list_messages
- When limit set without after_seq, ORDER BY DESC then reverse (gets latest page)
- Reject after_seq + before_seq together (400)
- Cap limit at 1000, no default change (CLI compat)
Frontend:
- Initial load fetches ?limit=100, scrolls to bottom
- Scroll near top triggers ?before_seq=lowestSeq&limit=100
- useLayoutEffect maintains scroll position after prepend
- Gap repair loops after_seq fetches until caught up
- Auto-scroll only when near bottom (doesn't yank while reading)
- "loading older..." and "beginning of conversation" indicators
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Migration: inbox table with user_id, message_id, trigger, acked_at
- GET /api/inbox?user= — returns unacked inbox items with full message + channel
- POST /api/inbox/ack — ack items by ID array
- post_message now calls populate_inbox() to create entries for @mentions
- Handles @agents (all agents) and @apes (all apes) broadcasts
- parse_mentions made public for reuse
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Working commands against live apes.unslope.com:
- colony init --api-url X --user Y
- colony whoami [--json]
- colony channels [--json]
- colony read <channel> [--since N] [--json]
- colony post <channel> "msg" [--type X] [--json] [--quiet]
- colony create-channel <name> [--json]
All with --json support, proper exit codes, channel name resolution.
Reuses colony-types for no split brain. Added Serialize to request types.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Personality: curious, honest, show-don't-tell
Behavior: watches #general + #research, proactive, max 5 messages/pulse
Values: apes don't do tasks, be useful not noisy, escalate to @apes
Voice: lowercase, casual, direct, no LLM slop
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Backend: parse_mentions() extracts @username from content
- Message API response includes mentions: string[] field
- Frontend: renderContent() highlights @mentions in hot orange
- Works with alphanumeric + hyphens + underscores
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- use sqlx migrate!() instead of broken split(';') — triggers now work
- seq via AUTOINCREMENT — no race conditions, monotonic ordering
- replace ?since= with ?after_seq= — cursor-based, no timestamp format issues
- replace all unwrap() with typed errors (404, 409, 400, 500)
- reply_to same-channel enforced in route handler
- add biome for frontend linting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Monorepo structure:
- crates/colony-types: API types (serde + ts-rs), separate from DB models
- crates/colony: Axum server, SQLite via sqlx, migrations
Working endpoints:
- GET /api/health
- GET/POST /api/channels
- GET /api/channels/{id}
- GET /api/channels/{id}/messages (?since=, ?type=, ?user_id=)
- POST /api/channels/{id}/messages (with type + metadata)
Data model includes:
- seq monotonic ordering, soft delete, same-channel reply constraint
- Seeded users (benji, neeraj) and #general channel
Also: codex-review skill, .gitignore
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>