refactor: rename container/ to runners/

No longer using Docker containers — agents run as direct host
processes. The directory name now reflects the actual purpose.

Updated all references across source code, docs, and skills.
This commit is contained in:
Eyejoker
2026-03-15 19:29:23 +09:00
parent 6f4b6f8df7
commit e2d6476cdf
28 changed files with 75 additions and 75 deletions

View File

@@ -34,7 +34,7 @@ This adds:
- `src/session-commands.ts` (extract and authorize session commands) - `src/session-commands.ts` (extract and authorize session commands)
- `src/session-commands.test.ts` (unit tests for command parsing and auth) - `src/session-commands.test.ts` (unit tests for command parsing and auth)
- Session command interception in `src/index.ts` (both `processGroupMessages` and `startMessageLoop`) - Session command interception in `src/index.ts` (both `processGroupMessages` and `startMessageLoop`)
- Slash command handling in `container/agent-runner/src/index.ts` - Slash command handling in `runners/agent-runner/src/index.ts`
### Validate ### Validate
@@ -46,7 +46,7 @@ npm run build
### Rebuild container ### Rebuild container
```bash ```bash
./container/build.sh ./runners/build.sh
``` ```
### Restart service ### Restart service
@@ -106,7 +106,7 @@ cd /tmp/nanoclaw-test
claude # then run /add-compact claude # then run /add-compact
npm run build npm run build
npm test npm test
./container/build.sh ./runners/build.sh
# Manual: send /compact from main group, verify compaction + continuation # Manual: send /compact from main group, verify compaction + continuation
# Manual: send @<assistant> /compact from non-main as non-admin, verify denial # Manual: send @<assistant> /compact from non-main as non-admin, verify denial
# Manual: send @<assistant> /compact from non-main as admin, verify allowed # Manual: send @<assistant> /compact from non-main as admin, verify allowed

View File

@@ -48,7 +48,7 @@ This merges in:
- `src/channels/gmail.test.ts` (unit tests) - `src/channels/gmail.test.ts` (unit tests)
- `import './gmail.js'` appended to the channel barrel file `src/channels/index.ts` - `import './gmail.js'` appended to the channel barrel file `src/channels/index.ts`
- Gmail credentials mount (`~/.gmail-mcp`) in `src/container-runner.ts` - Gmail credentials mount (`~/.gmail-mcp`) in `src/container-runner.ts`
- Gmail MCP server (`@gongrzhe/server-gmail-autoauth-mcp`) and `mcp__gmail__*` allowed tool in `container/agent-runner/src/index.ts` - Gmail MCP server (`@gongrzhe/server-gmail-autoauth-mcp`) and `mcp__gmail__*` allowed tool in `runners/agent-runner/src/index.ts`
- `googleapis` npm dependency in `package.json` - `googleapis` npm dependency in `package.json`
If the merge reports conflicts, resolve them by reading the conflicted files and understanding the intent of both sides. If the merge reports conflicts, resolve them by reading the conflicted files and understanding the intent of both sides.
@@ -199,7 +199,7 @@ npx -y @gongrzhe/server-gmail-autoauth-mcp
### Tool-only mode ### Tool-only mode
1. Remove `~/.gmail-mcp` mount from `src/container-runner.ts` 1. Remove `~/.gmail-mcp` mount from `src/container-runner.ts`
2. Remove `gmail` MCP server and `mcp__gmail__*` from `container/agent-runner/src/index.ts` 2. Remove `gmail` MCP server and `mcp__gmail__*` from `runners/agent-runner/src/index.ts`
3. Rebuild and restart 3. Rebuild and restart
4. Clear stale agent-runner copies: `rm -r data/sessions/*/agent-runner-src 2>/dev/null || true` 4. Clear stale agent-runner copies: `rm -r data/sessions/*/agent-runner-src 2>/dev/null || true`
5. Rebuild: `cd container && ./build.sh && cd .. && npm run build && launchctl kickstart -k gui/$(id -u)/com.nanoclaw` (macOS) or `systemctl --user restart nanoclaw` (Linux) 5. Rebuild: `cd container && ./build.sh && cd .. && npm run build && launchctl kickstart -k gui/$(id -u)/com.nanoclaw` (macOS) or `systemctl --user restart nanoclaw` (Linux)
@@ -209,7 +209,7 @@ npx -y @gongrzhe/server-gmail-autoauth-mcp
1. Delete `src/channels/gmail.ts` and `src/channels/gmail.test.ts` 1. Delete `src/channels/gmail.ts` and `src/channels/gmail.test.ts`
2. Remove `import './gmail.js'` from `src/channels/index.ts` 2. Remove `import './gmail.js'` from `src/channels/index.ts`
3. Remove `~/.gmail-mcp` mount from `src/container-runner.ts` 3. Remove `~/.gmail-mcp` mount from `src/container-runner.ts`
4. Remove `gmail` MCP server and `mcp__gmail__*` from `container/agent-runner/src/index.ts` 4. Remove `gmail` MCP server and `mcp__gmail__*` from `runners/agent-runner/src/index.ts`
5. Uninstall: `npm uninstall googleapis` 5. Uninstall: `npm uninstall googleapis`
6. Rebuild and restart 6. Rebuild and restart
7. Clear stale agent-runner copies: `rm -r data/sessions/*/agent-runner-src 2>/dev/null || true` 7. Clear stale agent-runner copies: `rm -r data/sessions/*/agent-runner-src 2>/dev/null || true`

View File

@@ -40,7 +40,7 @@ This merges in:
- `src/image.test.ts` (8 unit tests) - `src/image.test.ts` (8 unit tests)
- Image attachment handling in `src/channels/whatsapp.ts` - Image attachment handling in `src/channels/whatsapp.ts`
- Image passing to agent in `src/index.ts` and `src/container-runner.ts` - Image passing to agent in `src/index.ts` and `src/container-runner.ts`
- Image content block support in `container/agent-runner/src/index.ts` - Image content block support in `runners/agent-runner/src/index.ts`
- `sharp` npm dependency in `package.json` - `sharp` npm dependency in `package.json`
If the merge reports conflicts, resolve them by reading the conflicted files and understanding the intent of both sides. If the merge reports conflicts, resolve them by reading the conflicted files and understanding the intent of both sides.
@@ -59,13 +59,13 @@ All tests must pass and build must be clean before proceeding.
1. Rebuild the container (agent-runner changes need a rebuild): 1. Rebuild the container (agent-runner changes need a rebuild):
```bash ```bash
./container/build.sh ./runners/build.sh
``` ```
2. Sync agent-runner source to group caches: 2. Sync agent-runner source to group caches:
```bash ```bash
for dir in data/sessions/*/agent-runner-src/; do for dir in data/sessions/*/agent-runner-src/; do
cp container/agent-runner/src/*.ts "$dir" cp runners/agent-runner/src/*.ts "$dir"
done done
``` ```

View File

@@ -15,7 +15,7 @@ Tools added:
### Check if already applied ### Check if already applied
Check if `container/agent-runner/src/ollama-mcp-stdio.ts` exists. If it does, skip to Phase 3 (Configure). Check if `runners/agent-runner/src/ollama-mcp-stdio.ts` exists. If it does, skip to Phase 3 (Configure).
### Check prerequisites ### Check prerequisites
@@ -59,9 +59,9 @@ git merge upstream/skill/ollama-tool
``` ```
This merges in: This merges in:
- `container/agent-runner/src/ollama-mcp-stdio.ts` (Ollama MCP server) - `runners/agent-runner/src/ollama-mcp-stdio.ts` (Ollama MCP server)
- `scripts/ollama-watch.sh` (macOS notification watcher) - `scripts/ollama-watch.sh` (macOS notification watcher)
- Ollama MCP config in `container/agent-runner/src/index.ts` (allowedTools + mcpServers) - Ollama MCP config in `runners/agent-runner/src/index.ts` (allowedTools + mcpServers)
- `[OLLAMA]` log surfacing in `src/container-runner.ts` - `[OLLAMA]` log surfacing in `src/container-runner.ts`
- `OLLAMA_HOST` in `.env.example` - `OLLAMA_HOST` in `.env.example`
@@ -73,8 +73,8 @@ Existing groups have a cached copy of the agent-runner source. Copy the new file
```bash ```bash
for dir in data/sessions/*/agent-runner-src; do for dir in data/sessions/*/agent-runner-src; do
cp container/agent-runner/src/ollama-mcp-stdio.ts "$dir/" cp runners/agent-runner/src/ollama-mcp-stdio.ts "$dir/"
cp container/agent-runner/src/index.ts "$dir/" cp runners/agent-runner/src/index.ts "$dir/"
done done
``` ```
@@ -82,7 +82,7 @@ done
```bash ```bash
npm run build npm run build
./container/build.sh ./runners/build.sh
``` ```
Build must be clean before proceeding. Build must be clean before proceeding.
@@ -138,9 +138,9 @@ Look for:
### Agent says "Ollama is not installed" ### Agent says "Ollama is not installed"
The agent is trying to run `ollama` CLI inside the container instead of using the MCP tools. This means: The agent is trying to run `ollama` CLI inside the container instead of using the MCP tools. This means:
1. The MCP server wasn't registered — check `container/agent-runner/src/index.ts` has the `ollama` entry in `mcpServers` 1. The MCP server wasn't registered — check `runners/agent-runner/src/index.ts` has the `ollama` entry in `mcpServers`
2. The per-group source wasn't updated — re-copy files (see Phase 2) 2. The per-group source wasn't updated — re-copy files (see Phase 2)
3. The container wasn't rebuilt — run `./container/build.sh` 3. The container wasn't rebuilt — run `./runners/build.sh`
### "Failed to connect to Ollama" ### "Failed to connect to Ollama"

View File

@@ -78,7 +78,7 @@ const allowedVars = ['CLAUDE_CODE_OAUTH_TOKEN', 'ANTHROPIC_API_KEY', 'PARALLEL_A
### 4. Configure MCP Servers in Agent Runner ### 4. Configure MCP Servers in Agent Runner
Update `container/agent-runner/src/index.ts`: Update `runners/agent-runner/src/index.ts`:
Find the section where `mcpServers` is configured (around line 237-252): Find the section where `mcpServers` is configured (around line 237-252):
```typescript ```typescript
@@ -219,7 +219,7 @@ AskUserQuestion: I can do deep research on [topic] using Parallel's Task API. Th
Build the container with updated agent runner: Build the container with updated agent runner:
```bash ```bash
./container/build.sh ./runners/build.sh
``` ```
Verify the build: Verify the build:
@@ -286,5 +286,5 @@ To remove Parallel AI integration:
1. Remove from .env: `sed -i.bak '/PARALLEL_API_KEY/d' .env` 1. Remove from .env: `sed -i.bak '/PARALLEL_API_KEY/d' .env`
2. Revert changes to container-runner.ts and agent-runner/src/index.ts 2. Revert changes to container-runner.ts and agent-runner/src/index.ts
3. Remove Web Research Tools section from groups/main/CLAUDE.md 3. Remove Web Research Tools section from groups/main/CLAUDE.md
4. Rebuild: `./container/build.sh && npm run build` 4. Rebuild: `./runners/build.sh && npm run build`
5. Restart: `launchctl kickstart -k gui/$(id -u)/com.nanoclaw` (macOS) or `systemctl --user restart nanoclaw` (Linux) 5. Restart: `launchctl kickstart -k gui/$(id -u)/com.nanoclaw` (macOS) or `systemctl --user restart nanoclaw` (Linux)

View File

@@ -9,7 +9,7 @@ Adds PDF reading capability to all container agents using poppler-utils (pdftote
## Phase 1: Pre-flight ## Phase 1: Pre-flight
1. Check if `container/skills/pdf-reader/pdf-reader` exists — skip to Phase 3 if already applied 1. Check if `runners/skills/pdf-reader/pdf-reader` exists — skip to Phase 3 if already applied
2. Confirm WhatsApp is installed first (`skill/whatsapp` merged). This skill modifies WhatsApp channel files. 2. Confirm WhatsApp is installed first (`skill/whatsapp` merged). This skill modifies WhatsApp channel files.
## Phase 2: Apply Code Changes ## Phase 2: Apply Code Changes
@@ -34,9 +34,9 @@ git merge whatsapp/skill/pdf-reader
``` ```
This merges in: This merges in:
- `container/skills/pdf-reader/SKILL.md` (agent-facing documentation) - `runners/skills/pdf-reader/SKILL.md` (agent-facing documentation)
- `container/skills/pdf-reader/pdf-reader` (CLI script) - `runners/skills/pdf-reader/pdf-reader` (CLI script)
- `poppler-utils` in `container/Dockerfile` - `poppler-utils` in `runners/Dockerfile`
- PDF attachment download in `src/channels/whatsapp.ts` - PDF attachment download in `src/channels/whatsapp.ts`
- PDF tests in `src/channels/whatsapp.test.ts` - PDF tests in `src/channels/whatsapp.test.ts`
@@ -52,7 +52,7 @@ npx vitest run src/channels/whatsapp.test.ts
### Rebuild container ### Rebuild container
```bash ```bash
./container/build.sh ./runners/build.sh
``` ```
### Restart service ### Restart service
@@ -89,7 +89,7 @@ Look for:
### Agent says pdf-reader command not found ### Agent says pdf-reader command not found
Container needs rebuilding. Run `./container/build.sh` and restart the service. Container needs rebuilding. Run `./runners/build.sh` and restart the service.
### PDF text extraction is empty ### PDF text extraction is empty

View File

@@ -44,8 +44,8 @@ This adds:
- `scripts/migrate-reactions.ts` (database migration for `reactions` table with composite PK and indexes) - `scripts/migrate-reactions.ts` (database migration for `reactions` table with composite PK and indexes)
- `src/status-tracker.ts` (forward-only emoji state machine for message lifecycle signaling, with persistence and retry) - `src/status-tracker.ts` (forward-only emoji state machine for message lifecycle signaling, with persistence and retry)
- `src/status-tracker.test.ts` (unit tests for StatusTracker) - `src/status-tracker.test.ts` (unit tests for StatusTracker)
- `container/skills/reactions/SKILL.md` (agent-facing documentation for the `react_to_message` MCP tool) - `runners/skills/reactions/SKILL.md` (agent-facing documentation for the `react_to_message` MCP tool)
- Reaction support in `src/db.ts`, `src/channels/whatsapp.ts`, `src/types.ts`, `src/ipc.ts`, `src/index.ts`, `src/group-queue.ts`, and `container/agent-runner/src/ipc-mcp-stdio.ts` - Reaction support in `src/db.ts`, `src/channels/whatsapp.ts`, `src/types.ts`, `src/ipc.ts`, `src/index.ts`, `src/group-queue.ts`, and `runners/agent-runner/src/ipc-mcp-stdio.ts`
### Run database migration ### Run database migration

View File

@@ -168,7 +168,7 @@ export async function sendPoolMessage(
### Step 3: Add sender Parameter to MCP Tool ### Step 3: Add sender Parameter to MCP Tool
Read `container/agent-runner/src/ipc-mcp-stdio.ts` and update the `send_message` tool to accept an optional `sender` parameter: Read `runners/agent-runner/src/ipc-mcp-stdio.ts` and update the `send_message` tool to accept an optional `sender` parameter:
Change the tool's schema from: Change the tool's schema from:
```typescript ```typescript
@@ -320,7 +320,7 @@ Also add `TELEGRAM_BOT_POOL` to the launchd plist (`~/Library/LaunchAgents/com.n
```bash ```bash
npm run build npm run build
./container/build.sh # Required — MCP tool changed ./runners/build.sh # Required — MCP tool changed
# macOS: # macOS:
launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist
launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist
@@ -378,7 +378,7 @@ To remove Agent Swarm support while keeping basic Telegram:
2. Remove pool code from `src/telegram.ts` (`poolApis`, `senderBotMap`, `initBotPool`, `sendPoolMessage`) 2. Remove pool code from `src/telegram.ts` (`poolApis`, `senderBotMap`, `initBotPool`, `sendPoolMessage`)
3. Remove pool routing from IPC handler in `src/index.ts` (revert to plain `sendMessage`) 3. Remove pool routing from IPC handler in `src/index.ts` (revert to plain `sendMessage`)
4. Remove `initBotPool` call from `main()` 4. Remove `initBotPool` call from `main()`
5. Remove `sender` param from MCP tool in `container/agent-runner/src/ipc-mcp-stdio.ts` 5. Remove `sender` param from MCP tool in `runners/agent-runner/src/ipc-mcp-stdio.ts`
6. Remove Agent Teams section from group CLAUDE.md files 6. Remove Agent Teams section from group CLAUDE.md files
7. Remove `TELEGRAM_BOT_POOL` from `.env`, `data/env/env`, and launchd plist/systemd unit 7. Remove `TELEGRAM_BOT_POOL` from `.env`, `data/env/env`, and launchd plist/systemd unit
8. Rebuild: `npm run build && ./container/build.sh && launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist && launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist` (macOS) or `npm run build && ./container/build.sh && systemctl --user restart nanoclaw` (Linux) 8. Rebuild: `npm run build && ./runners/build.sh && launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist && launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist` (macOS) or `npm run build && ./runners/build.sh && systemctl --user restart nanoclaw` (Linux)

View File

@@ -72,8 +72,8 @@ This merges in:
- `src/container-runtime.ts` — Apple Container implementation (replaces Docker) - `src/container-runtime.ts` — Apple Container implementation (replaces Docker)
- `src/container-runtime.test.ts` — Apple Container-specific tests - `src/container-runtime.test.ts` — Apple Container-specific tests
- `src/container-runner.ts` — .env shadow mount fix and privilege dropping - `src/container-runner.ts` — .env shadow mount fix and privilege dropping
- `container/Dockerfile` — entrypoint that shadows .env via `mount --bind` - `runners/Dockerfile` — entrypoint that shadows .env via `mount --bind`
- `container/build.sh` — default runtime set to `container` - `runners/build.sh` — default runtime set to `container`
If the merge reports conflicts, resolve them by reading the conflicted files and understanding the intent of both sides. If the merge reports conflicts, resolve them by reading the conflicted files and understanding the intent of both sides.
@@ -97,7 +97,7 @@ container system status || container system start
### Build the container image ### Build the container image
```bash ```bash
./container/build.sh ./runners/build.sh
``` ```
### Test basic execution ### Test basic execution
@@ -158,7 +158,7 @@ container system status
```bash ```bash
# Clean rebuild — Apple Container caches aggressively # Clean rebuild — Apple Container caches aggressively
container builder stop && container builder rm && container builder start container builder stop && container builder rm && container builder start
./container/build.sh ./runners/build.sh
``` ```
**Container can't write to mounted directories:** **Container can't write to mounted directories:**
@@ -171,5 +171,5 @@ Check directory permissions on the host. The container runs as uid 1000.
| `src/container-runtime.ts` | Full replacement — Docker → Apple Container API | | `src/container-runtime.ts` | Full replacement — Docker → Apple Container API |
| `src/container-runtime.test.ts` | Full replacement — tests for Apple Container behavior | | `src/container-runtime.test.ts` | Full replacement — tests for Apple Container behavior |
| `src/container-runner.ts` | .env shadow mount removed, main containers start as root with privilege drop | | `src/container-runner.ts` | .env shadow mount removed, main containers start as root with privilege drop |
| `container/Dockerfile` | Entrypoint: `mount --bind` for .env shadowing, `setpriv` privilege drop | | `runners/Dockerfile` | Entrypoint: `mount --bind` for .env shadowing, `setpriv` privilege drop |
| `container/build.sh` | Default runtime: `docker``container` | | `runners/build.sh` | Default runtime: `docker``container` |

View File

@@ -12,7 +12,7 @@ This guide covers debugging the containerized agent execution system.
``` ```
Host (macOS) Container (Linux VM) Host (macOS) Container (Linux VM)
───────────────────────────────────────────────────────────── ─────────────────────────────────────────────────────────────
src/container-runner.ts container/agent-runner/ src/container-runner.ts runners/agent-runner/
│ │ │ │
│ spawns container │ runs Claude Agent SDK │ spawns container │ runs Claude Agent SDK
│ with volume mounts │ with MCP servers │ with volume mounts │ with MCP servers
@@ -234,11 +234,11 @@ query({
npm run build npm run build
# Rebuild container (use --no-cache for clean rebuild) # Rebuild container (use --no-cache for clean rebuild)
./container/build.sh ./runners/build.sh
# Or force full rebuild # Or force full rebuild
docker builder prune -af docker builder prune -af
./container/build.sh ./runners/build.sh
``` ```
## Checking Container Image ## Checking Container Image
@@ -332,7 +332,7 @@ echo -e "\n3. Container runtime running?"
docker info &>/dev/null && echo "OK" || echo "NOT RUNNING - start Docker Desktop (macOS) or sudo systemctl start docker (Linux)" docker info &>/dev/null && echo "OK" || echo "NOT RUNNING - start Docker Desktop (macOS) or sudo systemctl start docker (Linux)"
echo -e "\n4. Container image exists?" echo -e "\n4. Container image exists?"
echo '{}' | docker run -i --entrypoint /bin/echo nanoclaw-agent:latest "OK" 2>/dev/null || echo "MISSING - run ./container/build.sh" echo '{}' | docker run -i --entrypoint /bin/echo nanoclaw-agent:latest "OK" 2>/dev/null || echo "MISSING - run ./runners/build.sh"
echo -e "\n5. Session mount path correct?" echo -e "\n5. Session mount path correct?"
grep -q "/home/node/.claude" src/container-runner.ts 2>/dev/null && echo "OK" || echo "WRONG - should mount to /home/node/.claude/, not /root/.claude/" grep -q "/home/node/.claude" src/container-runner.ts 2>/dev/null && echo "OK" || echo "WRONG - should mount to /home/node/.claude/, not /root/.claude/"

View File

@@ -11,7 +11,7 @@ Run setup steps automatically. Only pause when user action is required (channel
**UX Note:** Use `AskUserQuestion` for all user-facing questions. **UX Note:** Use `AskUserQuestion` for all user-facing questions.
**Architecture:** NanoClaw runs agents as direct host processes (no Docker/containers). Each agent type (Claude Code, Codex) has its own runner in `container/agent-runner/` and `container/codex-runner/`. **Architecture:** NanoClaw runs agents as direct host processes (no Docker/containers). Each agent type (Claude Code, Codex) has its own runner in `runners/agent-runner/` and `runners/codex-runner/`.
## 0. Git & Fork Setup ## 0. Git & Fork Setup
@@ -76,12 +76,12 @@ Run `npx tsx setup/index.ts --step environment` and parse the status block.
Run `npx tsx setup/index.ts --step runners` and parse the status block. Run `npx tsx setup/index.ts --step runners` and parse the status block.
This builds the agent runners that execute as host processes: This builds the agent runners that execute as host processes:
- `container/agent-runner/` — Claude Code agent (via Claude Agent SDK) - `runners/agent-runner/` — Claude Code agent (via Claude Agent SDK)
- `container/codex-runner/` — Codex agent (via Codex CLI) - `runners/codex-runner/` — Codex agent (via Codex CLI)
**If BUILD_OK=false:** Read `logs/setup.log` for the error. Common fix: `cd container/agent-runner && npm install && npm run build`. **If BUILD_OK=false:** Read `logs/setup.log` for the error. Common fix: `cd runners/agent-runner && npm install && npm run build`.
**If CODEX_RUNNER=false but AGENT_RUNNER=true:** Codex runner failed to build. Not critical if you only use Claude Code. Fix: `cd container/codex-runner && npm install && npm run build`. **If CODEX_RUNNER=false but AGENT_RUNNER=true:** Codex runner failed to build. Not critical if you only use Claude Code. Fix: `cd runners/codex-runner && npm install && npm run build`.
## 4. Claude Authentication (No Script) ## 4. Claude Authentication (No Script)

View File

@@ -18,7 +18,7 @@ Run `/update-nanoclaw` in Claude Code.
**Preview**: runs `git log` and `git diff` against the merge base to show upstream changes since your last sync. Groups changed files into categories: **Preview**: runs `git log` and `git diff` against the merge base to show upstream changes since your last sync. Groups changed files into categories:
- **Skills** (`.claude/skills/`): unlikely to conflict unless you edited an upstream skill - **Skills** (`.claude/skills/`): unlikely to conflict unless you edited an upstream skill
- **Source** (`src/`): may conflict if you modified the same files - **Source** (`src/`): may conflict if you modified the same files
- **Build/config** (`package.json`, `tsconfig*.json`, `container/`): review needed - **Build/config** (`package.json`, `tsconfig*.json`, `runners/`): review needed
**Update paths** (you pick one): **Update paths** (you pick one):
- `merge` (default): `git merge upstream/<branch>`. Resolves all conflicts in one pass. - `merge` (default): `git merge upstream/<branch>`. Resolves all conflicts in one pass.
@@ -109,7 +109,7 @@ Show file-level impact from upstream:
Bucket the upstream changed files: Bucket the upstream changed files:
- **Skills** (`.claude/skills/`): unlikely to conflict unless the user edited an upstream skill - **Skills** (`.claude/skills/`): unlikely to conflict unless the user edited an upstream skill
- **Source** (`src/`): may conflict if user modified the same files - **Source** (`src/`): may conflict if user modified the same files
- **Build/config** (`package.json`, `package-lock.json`, `tsconfig*.json`, `container/`, `launchd/`): review needed - **Build/config** (`package.json`, `package-lock.json`, `tsconfig*.json`, `runners/`, `launchd/`): review needed
- **Other**: docs, tests, misc - **Other**: docs, tests, misc
Present these buckets to the user and ask them to choose one path using AskUserQuestion: Present these buckets to the user and ask them to choose one path using AskUserQuestion:

View File

@@ -44,7 +44,7 @@ npx dotenv -e .env -- npx tsx .claude/skills/x-integration/scripts/setup.ts
# Verify: data/x-auth.json should exist after successful login # Verify: data/x-auth.json should exist after successful login
# 2. Rebuild container to include skill # 2. Rebuild container to include skill
./container/build.sh ./runners/build.sh
# Verify: Output shows "COPY .claude/skills/x-integration/agent.ts" # Verify: Output shows "COPY .claude/skills/x-integration/agent.ts"
# 3. Rebuild host and restart service # 3. Rebuild host and restart service
@@ -181,7 +181,7 @@ if (!handled) {
--- ---
**2. Container side: `container/agent-runner/src/ipc-mcp.ts`** **2. Container side: `runners/agent-runner/src/ipc-mcp.ts`**
Add import after `cron-parser` import: Add import after `cron-parser` import:
```typescript ```typescript
@@ -196,21 +196,21 @@ Add to the end of tools array (before the closing `]`):
--- ---
**3. Build script: `container/build.sh`** **3. Build script: `runners/build.sh`**
Change build context from `container/` to project root (required to access `.claude/skills/`): Change build context from `runners/` to project root (required to access `.claude/skills/`):
```bash ```bash
# Find: # Find:
docker build -t "${IMAGE_NAME}:${TAG}" . docker build -t "${IMAGE_NAME}:${TAG}" .
# Replace with: # Replace with:
cd "$SCRIPT_DIR/.." cd "$SCRIPT_DIR/.."
docker build -t "${IMAGE_NAME}:${TAG}" -f container/Dockerfile . docker build -t "${IMAGE_NAME}:${TAG}" -f runners/Dockerfile .
``` ```
--- ---
**4. Dockerfile: `container/Dockerfile`** **4. Dockerfile: `runners/Dockerfile`**
First, update the build context paths (required to access `.claude/skills/` from project root): First, update the build context paths (required to access `.claude/skills/` from project root):
```dockerfile ```dockerfile
@@ -220,12 +220,12 @@ COPY agent-runner/package*.json ./
COPY agent-runner/ ./ COPY agent-runner/ ./
# Replace with: # Replace with:
COPY container/agent-runner/package*.json ./ COPY runners/agent-runner/package*.json ./
... ...
COPY container/agent-runner/ ./ COPY runners/agent-runner/ ./
``` ```
Then add COPY line after `COPY container/agent-runner/ ./` and before `RUN npm run build`: Then add COPY line after `COPY runners/agent-runner/ ./` and before `RUN npm run build`:
```dockerfile ```dockerfile
# Copy skill MCP tools # Copy skill MCP tools
COPY .claude/skills/x-integration/agent.ts ./src/skills/x-integration/ COPY .claude/skills/x-integration/agent.ts ./src/skills/x-integration/
@@ -260,12 +260,12 @@ cat data/x-auth.json # Should show {"authenticated": true, ...}
### 3. Rebuild Container ### 3. Rebuild Container
```bash ```bash
./container/build.sh ./runners/build.sh
``` ```
**Verify success:** **Verify success:**
```bash ```bash
./container/build.sh 2>&1 | grep -i "agent.ts" # Should show COPY line ./runners/build.sh 2>&1 | grep -i "agent.ts" # Should show COPY line
``` ```
### 4. Restart Service ### 4. Restart Service
@@ -403,7 +403,7 @@ If MCP tools not found in container:
```bash ```bash
# Verify build copies skill # Verify build copies skill
./container/build.sh 2>&1 | grep -i skill ./runners/build.sh 2>&1 | grep -i skill
# Check container has the file # Check container has the file
docker run nanoclaw-agent ls -la /app/src/skills/ docker run nanoclaw-agent ls -la /app/src/skills/

View File

@@ -18,8 +18,8 @@ Two systemd services (`nanoclaw`, `nanoclaw-codex`) share the same codebase but
| `src/config.ts` | Trigger pattern, paths, intervals | | `src/config.ts` | Trigger pattern, paths, intervals |
| `src/task-scheduler.ts` | Runs scheduled tasks | | `src/task-scheduler.ts` | Runs scheduled tasks |
| `src/db.ts` | SQLite operations | | `src/db.ts` | SQLite operations |
| `container/agent-runner/` | Claude Code runner (Agent SDK) | | `runners/agent-runner/` | Claude Code runner (Agent SDK) |
| `container/codex-runner/` | Codex runner (SDK, `codex exec` wrapper) | | `runners/codex-runner/` | Codex runner (SDK, `codex exec` wrapper) |
| `groups/{name}/CLAUDE.md` | Per-group memory (isolated) | | `groups/{name}/CLAUDE.md` | Per-group memory (isolated) |
## Skills ## Skills

View File

@@ -60,7 +60,7 @@ nanoclaw/
│ └── channels/ │ └── channels/
│ ├── registry.ts # Channel self-registration system │ ├── registry.ts # Channel self-registration system
│ └── discord.ts # Discord: mentions, images, typing, file attachments │ └── discord.ts # Discord: mentions, images, typing, file attachments
├── container/ ├── runners/
│ ├── agent-runner/ # Claude Code runner (Agent SDK, multimodal input) │ ├── agent-runner/ # Claude Code runner (Agent SDK, multimodal input)
│ ├── codex-runner/ # Codex runner (app-server JSON-RPC, auto-continue) │ ├── codex-runner/ # Codex runner (app-server JSON-RPC, auto-continue)
│ └── skills/ # Shared agent skills (browser, etc.) │ └── skills/ # Shared agent skills (browser, etc.)
@@ -77,7 +77,7 @@ nanoclaw/
### Codex App-Server Integration ### Codex App-Server Integration
The Codex runner (`container/codex-runner/`) communicates with `codex app-server` via JSON-RPC over stdio: The Codex runner (`runners/codex-runner/`) communicates with `codex app-server` via JSON-RPC over stdio:
- **Session persistence**: Thread IDs stored in DB, sessions saved as JSONL on disk - **Session persistence**: Thread IDs stored in DB, sessions saved as JSONL on disk
- **Streaming**: `item/agentMessage/delta` notifications for real-time text - **Streaming**: `item/agentMessage/delta` notifications for real-time text
@@ -98,7 +98,7 @@ Bidirectional image support through Discord:
Skills are managed from a single source of truth (`~/.claude/skills/` on the server) and automatically synced to all agent session directories at process start: Skills are managed from a single source of truth (`~/.claude/skills/` on the server) and automatically synced to all agent session directories at process start:
- Claude Code sessions: `~/.claude/skills/` + project `container/skills/` - Claude Code sessions: `~/.claude/skills/` + project `runners/skills/`
- Codex sessions: Same sources, synced to per-group `.codex/` directories - Codex sessions: Same sources, synced to per-group `.codex/` directories
- Skills auto-register as slash commands (`/name`) in Claude Code and `$name` in Codex - Skills auto-register as slash commands (`/name`) in Claude Code and `$name` in Codex

View File

@@ -268,7 +268,7 @@ nanoclaw/
│ ├── task-scheduler.ts # Runs scheduled tasks when due │ ├── task-scheduler.ts # Runs scheduled tasks when due
│ └── container-runner.ts # Spawns agents in containers │ └── container-runner.ts # Spawns agents in containers
├── container/ ├── runners/
│ ├── Dockerfile # Container image (runs as 'node' user, includes Claude Code CLI) │ ├── Dockerfile # Container image (runs as 'node' user, includes Claude Code CLI)
│ ├── build.sh # Build script for container image │ ├── build.sh # Build script for container image
│ ├── agent-runner/ # Code that runs inside the container │ ├── agent-runner/ # Code that runs inside the container

View File

@@ -6,7 +6,7 @@
"main": "dist/index.js", "main": "dist/index.js",
"scripts": { "scripts": {
"build": "tsc", "build": "tsc",
"build:runners": "cd container/agent-runner && npm install && npm run build && cd ../codex-runner && npm install && npm run build", "build:runners": "cd runners/agent-runner && npm install && npm run build && cd ../codex-runner && npm install && npm run build",
"start": "node dist/index.js", "start": "node dist/index.js",
"dev": "tsx src/index.ts", "dev": "tsx src/index.ts",
"typecheck": "tsc --noEmit", "typecheck": "tsc --noEmit",

View File

@@ -82,14 +82,14 @@ function prepareGroupEnvironment(
} }
// Sync skills into each group's .claude/ session dir // Sync skills into each group's .claude/ session dir
// Sources: 1) user's global ~/.claude/skills 2) project workDir/.claude/skills 3) container/skills/ // Sources: 1) user's global ~/.claude/skills 2) project workDir/.claude/skills 3) runners/skills/
const workDirClaude = group.workDir const workDirClaude = group.workDir
? path.join(group.workDir, '.claude') ? path.join(group.workDir, '.claude')
: null; : null;
const skillSources = [ const skillSources = [
path.join(os.homedir(), '.claude', 'skills'), path.join(os.homedir(), '.claude', 'skills'),
...(workDirClaude ? [path.join(workDirClaude, 'skills')] : []), ...(workDirClaude ? [path.join(workDirClaude, 'skills')] : []),
path.join(projectRoot, 'container', 'skills'), path.join(projectRoot, 'runners', 'skills'),
]; ];
const skillsDst = path.join(groupSessionsDir, 'skills'); const skillsDst = path.join(groupSessionsDir, 'skills');
for (const src of skillSources) { for (const src of skillSources) {
@@ -128,7 +128,7 @@ function prepareGroupEnvironment(
// Determine runner directory // Determine runner directory
const agentType = group.agentType || 'claude-code'; const agentType = group.agentType || 'claude-code';
const runnerDirName = agentType === 'codex' ? 'codex-runner' : 'agent-runner'; const runnerDirName = agentType === 'codex' ? 'codex-runner' : 'agent-runner';
const runnerDir = path.join(projectRoot, 'container', runnerDirName); const runnerDir = path.join(projectRoot, 'runners', runnerDirName);
// Build environment variables for the runner process // Build environment variables for the runner process
const envVars = readEnvFile([ const envVars = readEnvFile([
@@ -222,10 +222,10 @@ function prepareGroupEnvironment(
} }
} }
// Sync skills into Codex session dir // Sync skills into Codex session dir
// SSOT: ~/.claude/skills/ (shared with Claude Code) + container/skills/ // SSOT: ~/.claude/skills/ (shared with Claude Code) + runners/skills/
const codexSkillSources = [ const codexSkillSources = [
path.join(os.homedir(), '.claude', 'skills'), path.join(os.homedir(), '.claude', 'skills'),
path.join(projectRoot, 'container', 'skills'), path.join(projectRoot, 'runners', 'skills'),
]; ];
const codexSkillsDst = path.join(sessionCodexDir, 'skills'); const codexSkillsDst = path.join(sessionCodexDir, 'skills');
for (const src of codexSkillSources) { for (const src of codexSkillSources) {
@@ -245,7 +245,7 @@ function prepareGroupEnvironment(
// Inject nanoclaw MCP server into Codex config.toml // Inject nanoclaw MCP server into Codex config.toml
const mcpServerPath = path.join( const mcpServerPath = path.join(
projectRoot, projectRoot,
'container', 'runners',
'agent-runner', 'agent-runner',
'dist', 'dist',
'ipc-mcp-stdio.js', 'ipc-mcp-stdio.js',
@@ -333,7 +333,7 @@ export async function runAgentProcess(
if (!fs.existsSync(distEntry)) { if (!fs.existsSync(distEntry)) {
logger.error( logger.error(
{ runnerDir }, { runnerDir },
'Runner not built. Run: cd container/agent-runner && npm install && npm run build', 'Runner not built. Run: cd runners/agent-runner && npm install && npm run build',
); );
return { return {
status: 'error', status: 'error',