Container's /home/node/.claude always mounts the reviewer session dir.
When arbiter runs codex in the same container, CODEX_HOME reads from
reviewer session's .codex/. Copy arbiter AGENTS.md there so codex gets
arbiter prompts instead of reviewer prompts.
- Replace better-sqlite3 with bun:sqlite (native, no native addon build)
- Change all spawn('node') to spawn('bun') for agent processes
- Update package.json scripts: node→bun, tsx→bun, npm→bun
- Add bun-types for tsc compatibility
- Add bun:sqlite→better-sqlite3 shim for vitest (tests run on Node.js)
- Update Dockerfile: install bun alongside Node.js (CLIs need Node)
- Update setup/platform.ts: getNodePath() resolves bun binary
- Remove better-sqlite3 from production dependencies (devDep only for tests)
SERVICE_AGENT_TYPE was always 'claude-code' in the unified service,
making it a misleading constant. Each group already has its own
agentType field.
- Removed SERVICE_AGENT_TYPE from config.ts
- Session functions now accept agentType parameter (default: 'claude-code')
- Task scheduler uses task-level agent_type for token rotation decisions
- All fallback defaults changed to 'claude-code' literal
- Logging uses 'unified' instead of the misleading type
Container reviewer was running without prompts because the container
path in agent-runner.ts skipped prepareGroupEnvironment() entirely.
This meant no CLAUDE.md (platform + paired room prompts + memory
briefing) and no roomRoleContext were passed to the container.
- Add prepareContainerSessionEnvironment() to write CLAUDE.md, sync
skills, and ensure settings.json for the reviewer session directory
- Pass roomRoleContext through ReviewerContainerInput so the runner
can prepend the [ROOM_ROLE] header
- Add roomRoleContext field to ReviewerContainerInput interface
Reviewer always runs in Docker container. No more snapshot file copy —
reviewer mounts the owner workspace directly as read-only. Removes
REVIEWER_CONTAINER_ENABLED toggle and host-mode fallback code.
- Remove UNIFIED_MODE legacy: single service manages all 3 Discord bots
- Add OWNER_AGENT_TYPE / REVIEWER_AGENT_TYPE env vars for configurable agent selection
- Fix Discord channel routing: reviewer output goes through correct bot (discord/discord-review)
- Fix channel name assignment: explicit names prevent agentTypeFilter collision
- Remove silent output suppression system: harness-level protections replace prompt workarounds
- Add reviewer approval detection: DONE marker on first line stops ping-pong
- Include user's original message in reviewer prompt for context
- Fix round_trip_count auto-reset on new user message
- Fix session ID conflict: reviewer doesn't reuse owner's session
- Fix pending progress text flush in runner on close sentinel
- Promote buffered intermediate text to final result when result event has no text
- Remove legacy files: .env.codex.example, .env.codex-review.example, migrate-unify.cjs
- Update CLAUDE.md: server-side build deployment, unified architecture docs
Two bugs fixed:
1. agent-runner: process close handler only checked `code !== 0`,
but signal kills (SIGTERM/SIGKILL from post-close cleanup) set
code=null which was misclassified as error even after successful
output delivery. Now checks `code === null && signal` and resolves
as success when hadStreamingOutput is true.
2. message-agent-executor: wrappedOnOutput persisted newSessionId
before checking for poisoned session, allowing a stale session to
be re-saved after clearSession. Reordered to check poison first
and guard persist with !resetSessionRequested.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Merge remote main (token rotation, usage API, dashboard fixes)
with local memory pipeline changes. Smart quote encoding fixed.
Test alignment pending.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add automatic memory integration so EJClaw host directly calls Memento
MCP for recall at session start and reflect on compact, removing
reliance on agent voluntary tool use.
Stage 1: New sessions get room memory briefing injected into system
prompt (CLAUDE.md / AGENTS.md) via host-side MCP client.
Stage 2: PreCompact hook automatically calls reflect + remember to
persist session summaries as room-memory fragments.
Also restores missing source files (token-rotation, codex-token-rotation,
claude-usage exports) to fix full build from source.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Track each subagent separately via agentId from SDK task events.
Single subagent shows detailed view with activity sub-lines,
multiple subagents show compact one-line-each format.
Add 'intermediate' phase for assistant text between tool calls.
These are sent as separate Discord messages without finalizing
or disrupting the active progress message.
Display subagent tool descriptions as sub-lines under the main
progress text, updating in-place via Discord message edit.
Shows up to 5 recent tool activities (e.g., "Reading index.ts").
- Use system/task_progress subtype (not top-level type) for subagent events
- Extract intermediate assistant text between tool calls as progress
- Only show SDK-generated summaries for subagent progress (skip noisy per-tool updates)
- Truncate progress messages to Discord 2000 char limit
- Remove verbose debug logging from production
Major reliability improvements to the message processing pipeline:
- Add messages.seq monotonic cursor replacing timestamp-based cursors,
preventing message loss from timestamp collisions with LIMIT queries
- Add work_items table separating agent production from delivery,
enabling delivery retry without re-running the agent
- Propagate Discord send failures instead of silently swallowing them
- Add Claude 429 → Kimi K2.5 automatic provider fallback with cooldown
- Fix follow-up turn state reset in live index.ts path (not just
message-runtime.ts) to prevent final output from being lost
- Add restart context tracking for graceful restart announcements
- Lazy migration from timestamp cursors to seq cursors for existing data
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
watch_ci tasks in perf channel were silently failing because
NANOCLAW_CHAT_JID was set to the group folder name (e.g. "eyejokerdb-4")
instead of the actual Discord JID. The scheduler rejected the task with
"target group not registered".
Also adds a fallback in ipc.ts to resolve folder names to registered
JIDs when a folder name is passed instead of a JID.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two bugs fixed:
1. agent-runner error path race condition: when agent process exited
with error, the promise resolved immediately without waiting for
outputChain, allowing a late wrappedOnOutput to re-persist a stale
session ID after clearSession had already run.
2. follow-up turn state not resetting: when a follow-up IPC message
joined an active run, turn-level flags (finalOutputSentToUser,
sawNonProgressOutput) from the first turn prevented the last
progress from being promoted to a final message.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Delete token-refresh.ts and credentials.json sync. Auth is now
via CLAUDE_CODE_OAUTH_TOKEN in .env (1-year setup-token).
No more auto-refresh loop or credentials.json dependency.
- Remove commands/ sync from agent-runner (skills/ is SSOT for both agents)
- Remove ~/.codex/skills/ as source (use ~/.claude/skills/ only)
- Codex uses $skill prefix, Claude Code uses /skill — both read from skills/
- Minor formatting fixes in config.ts, group-queue.test.ts, index.ts
Codex sessions now also receive skills and commands from ~/.claude/
in addition to ~/.codex/, so both agents share the same tool set
(patch, linear, sentry, coolify, exa, playwright, sprite, etc.)