Commit Graph

257 Commits

Author SHA1 Message Date
Gabi Simons 5f8a138868 docs(skills): update add-matrix skill
- Install steps aligned with add-linear/add-github pattern (fetch,
  copy, import, install pkg, build)
- Add Matrix-specific step: patch @beeper/chat-adapter-matrix ESM
  imports (inline node one-liner, idempotent)
- Cover bot-account requirement (can't DM yourself), access-token
  and username/password auth paths, optional invite auto-join /
  E2EE / device-id settings
2026-04-20 11:01:37 +00:00
Koshkoshinski 4e1cee0e5b feat(new-setup-2): phase-2 setup skill + --no-cli-bonus flag
New /new-setup-2 skill, invoked when the user picks "continue setup"
at the end of /new-setup. Linear rollthrough; every step skippable:

  1. What should the agent call you?
  2. What's your agent's name?
  3. Messaging channel (plain list, no AskUserQuestion) — invokes the
     matching /add-<channel> skill, captures platform IDs from its
     output, then wires via init-first-agent.ts with --no-cli-bonus.
     On success, emits the encouragement line verbatim.
  4. Quality-of-life picks (dashboard, compact, karpathy-wiki, plus
     macos-statusbar only when the probe reports PLATFORM=darwin).
  5. Wrap-up.

scripts/init-first-agent.ts gains a --no-cli-bonus flag. In DM mode,
the bonus "wire new agent to CLI" call is skipped when set. Used by
/new-setup-2 so the throwaway CLI-only agent from /new-setup retains
clean single-agent ownership of CLI routing instead of being duelled
by the real agent on the same channel.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 10:44:03 +00:00
Koshkoshinski 2eb6907f09 feat(new-setup): silent CLI wiring + post-service branch point
Step 6 (CLI agent wiring + first chat) is now invisible to the user.
No prompts, no narration — just silent wiring with INFERRED_DISPLAY_NAME
and a background ping. On the ping's return, emit one line:

    Your agent is up, running and ready to go!

Step 7 becomes a branch point via AskUserQuestion: either keep chatting
via CLI (prints two how-to-chat options: the `!pnpm run chat` bang
method inside Claude Code, and the separate-terminal form), or continue
to /new-setup-2 for the post-install flow (naming, messaging channel,
QoL).

The CLI agent at this stage is a scratch agent — its only job is to
verify the end-to-end pipeline works. The real name capture happens in
/new-setup-2 when the user wires a messaging channel.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 10:44:03 +00:00
Ira Abramov ad97829151 docs(add-signal-v2): replace inline voice section with reference to add-voice-transcription-free-whisper
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 13:17:57 +03:00
Ira Abramov bc0b559461 docs(add-signal-v2): document XDG attachment path behaviour and voice fix
signal-sdk launches signal-cli without --config, so attachments land at
~/.local/share/signal-cli/attachments/ (XDG default) rather than
data/signal/. Document this in the Channel Info section and add a
troubleshooting entry explaining the symptom (voice messages silently
skipped, no transcript), how to confirm (ps aux | grep signal-cli), and
the automatic fallback the adapter uses.
2026-04-20 12:27:10 +03:00
Ira Abramov 06918f35e0 feat(channels): add Signal channel adapter (v2) — skill and docs
Adds the /add-signal-v2 skill: a native Signal channel adapter wrapping
signal-sdk (signal-cli under the hood). No bot API — NanoClaw registers
as a full Signal account on a dedicated number or as a linked device.

Features: text, group & DM routing, voice transcription via whisper.cpp,
attachments, emoji reactions, @mention detection, quote-reply detection.

Troubleshooting note updated: GroupV2 group ID lives at
envelope.dataMessage.groupV2.id — not groupInfo.groupId (GroupV1/legacy).
2026-04-20 12:11:51 +03:00
Tal Moskovich 0dae3498c3 docs(add-opencode): pin SDK/CLI to 1.4.17, document overlay propagation and env vars
- Pin @opencode-ai/sdk and opencode-ai CLI both to 1.4.17; warn against
  latest (1.14.x has a breaking session API rewrite incompatible with
  the current provider code)
- Add step 7: propagate provider files into existing per-group overlays
  (data/v2-sessions/*/agent-runner-src/providers/) which override the
  image at runtime and are never auto-updated by rebuilds
- Add build cache gotcha: prune builder if "Unknown provider" after rebuild
- Document ANTHROPIC_BASE_URL as required for non-anthropic providers,
  with correct base URL per provider (DeepSeek, OpenRouter examples)
- Add OPENCODE_SMALL_MODEL to all examples
- Document OneCLI credential grant (set-secrets replaces, not appends)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 23:06:11 +03:00
Gabi Simons 0d09c6ea21 docs(add-linear): OAuth app auth, bridge patch, team routing, wiring
Rewrite SKILL.md with tested setup: OAuth app with client credentials
(recommended), bridge catchAll patch for platforms without @-mention,
LINEAR_TEAM_KEY for team-based routing, webhook setup with delay note,
private vs public sender policy, and wiring example.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-19 15:45:02 +00:00
Gabi Simons 57ad3591a1 docs(add-github): document bot account, userName, sender policy, and wiring
Update SKILL.md with tested setup: dedicated bot account prerequisite,
GITHUB_BOT_USERNAME env var for @-mention detection, private vs public
repo sender policy guidance, member registration for strict mode,
per-thread session mode, and wiring example.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-19 12:47:52 +00:00
exe.dev user 96d7656112 refactor(new-setup): rewrite probe in pure bash, drop unavailable fallback
The probe now returns a real snapshot from second zero, so every step
consults real probe fields instead of falling back to "run every step
blindly" when Node isn't installed. Also drops the redundant
CLI_AGENT_WIRED field (it gated the last step on its own end-state) and
scopes timezone out of the probe (timezone is not part of /new-setup).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 12:40:53 +00:00
Koshkoshinsk 5542107b9e fix(new-setup): align onecli health path and rework auth flow
onecli step:
- Poll /api/health (was /health) so the step's health check matches
  the probe's. On hosted OneCLI (app.onecli.sh) the old path returned
  non-ok, flagging the gateway as "degraded" even though install
  succeeded.
- Drop the "try `onecli start`" hint — no such subcommand exists and
  it sent the skill off chasing fabricated commands. A failed health
  poll is demoted to a soft warning; the auth step surfaces a real
  outage via `onecli secrets list`.

SKILL.md step 4: rewrite to match the /setup skill's pattern — the
user generates the token themselves, picks dashboard or CLI to
register it with OneCLI, and the skill verifies via `auth --check`.
Tokens no longer travel through chat.

Co-Authored-By: Koshkoshinsk <daniel.milliner@gmail.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 12:10:21 +00:00
Koshkoshinsk 0992979c5a feat(new-setup): probe host-deps and skip bootstrap when already installed
Probe now emits HOST_DEPS (ok|missing) based on whether
node_modules/better-sqlite3/build/Release/better_sqlite3.node exists
— the canonical proof that `pnpm install` ran and the native build
step succeeded. Step 1 (Node bootstrap) skips when HOST_DEPS=ok
instead of always re-running setup.sh. Probe now genuinely routes
step 1 the same way it routes every other step.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 12:01:05 +00:00
Koshkoshinsk f553c8126c refactor(new-setup): add step-4 join barrier and drop scripted one-liners
Two flow fixes:

1. Add "Ordering and parallelism" section making explicit that step 4
   (auth) must block until step 3 (OneCLI) is complete — auth writes
   the secret into the vault, so firing an AskUserQuestion while
   OneCLI is still installing asks the user for a credential the
   system can't store. Step 2 (container build) is safe to run past
   step 4, joined before step 6 (first CLI agent).

2. Drop the per-step quoted one-liners. They duplicated Claude's own
   natural narration ("While those build, let's get your credential
   set up." → immediately echoed by the scripted "Your agent needs an
   Anthropic credential..."). Each step now has a short description
   instead; Claude narrates in its own voice.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 11:50:00 +00:00
Koshkoshinsk 77fec6c7c3 fix(new-setup): avoid double-bootstrap and corepack EACCES on system Node
Two fixes to the fresh-install path:

1. setup.sh: when `corepack enable` runs as a non-root user against a
   system-wide Node install (apt-installed to /usr/bin), it fails EACCES
   trying to symlink /usr/bin/pnpm, leaving pnpm off PATH. Retry with
   sudo when pnpm is still missing — gated to Linux/WSL so macOS
   Homebrew prefixes aren't polluted with root-owned shims.

2. SKILL.md step 1: if the probe reports STATUS: unavailable (Node not
   installed), install Node BEFORE invoking `bash setup.sh`. The old
   flow ran setup.sh first as a diagnostic, which always failed fast,
   installed Node, then re-ran — two bootstraps for no reason.

Combined: fresh Linux box now goes Node install -> single setup.sh run.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 11:37:03 +00:00
Koshkoshinsk 77624d7854 fix(new-setup): wrap probe in shell script for single-command permission check
The chained `&& / ||` inline command tripped Claude Code's per-operation
permission check. Move the Node-missing fallback into setup/probe.sh so
the skill's `!` block is a single `bash setup/probe.sh` call.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 11:05:54 +00:00
Koshkoshinsk b3e8b2e047 fix(new-setup): run probe before pnpm is installed
Port probe to zero-dep plain ESM (setup/probe.mjs) so /new-setup can
inject dynamic context on a fresh machine where pnpm/node_modules
don't yet exist. Skill falls back to a STATUS: unavailable block if
Node itself isn't on PATH, and the flow treats that as "run every
step from 1" (each step is idempotent).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 11:03:49 +00:00
Koshkoshinsk f6ddd20636 feat(new-setup): add skill definition
Shortest path from zero to a working two-way agent chat via the CLI
channel. Renders `!`pnpm exec tsx setup/index.ts --step probe`` at the
top for dynamic context injection — Claude sees current system state
before generating its first response and routes each subsequent step
(skip/ask/run) off the probe snapshot. Pre-approves the Bash patterns
it needs via `allowed-tools` so setup runs without per-step prompts.

Lives alongside /setup for now; will replace it once proven.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 10:43:41 +00:00
Bryan Lozano 47e3203809 feat: add /add-ollama-provider skill and docs/ollama.md
Adds a new operational skill that routes any agent group to a local
Ollama instance instead of the Anthropic API. Ollama speaks the
Anthropic /v1/messages endpoint natively, so no new provider code is
needed — just env var overrides and a model setting in the shared
settings file.

The skill also documents and applies two prerequisite source changes:
- ContainerConfig gains env and blockedHosts fields (container-config.ts)
- container-runner wires those fields as -e and --add-host Docker flags
- Dockerfile home dir set to chmod 777 so containers running as the
  host uid can write ~/.claude config (discovered during implementation)

docs/ollama.md covers the architecture, OneCLI proxy bypass rationale,
network isolation via blockedHosts, model selection tradeoffs for Apple
Silicon, and revert instructions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 01:11:46 -07:00
gavrielc c37609ffc8 docs(skills): drop "v2" from skill content + src/index.ts log lines
Cleans up the prose-level v2 references that the rename commit didn't
touch. Skills now describe themselves and the codebase without "v2"
versioning language. /add-X-v2 cross-references in setup, init-first-agent,
and manage-channels updated to /add-X.

Runtime path identifiers (data/v2.db, data/v2-sessions/, container name
nanoclaw-v2) deliberately left as-is — renaming them breaks live installs
without commensurate benefit.

Verified: pnpm run build clean, 326 host tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 14:42:55 +03:00
gavrielc 00fb1bee4a chore(skills): rename add-*-v2 → add-* and drop dead v1 channel skills
Renamed 13 skill folders to drop the -v2 suffix (the v2/v1 distinction
isn't load-bearing anymore — there is no v1 runtime). Deleted the four
v1 channel skills that occupied the rename target paths (add-discord,
add-slack, add-telegram, add-whatsapp); they targeted src/v1 which is
reference-only per CLAUDE.md.

Skill content still says "v2" in places — that's a follow-up commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 14:38:19 +03:00
gavrielc 4857512267 refactor(v2): move setup/groups.ts off trunk + drop pino dep
setup/groups.ts is whatsapp-only — its inline syncScript imports baileys
and pino to fetch group metadata via Baileys.groupFetchAllParticipating.
On trunk it was a no-op for non-whatsapp users (returned early without
auth) and the only thing keeping pino alive.

Removed:
- setup/groups.ts (lives on `channels` branch; restored by /add-whatsapp-v2)
- `groups` STEPS entry from setup/index.ts
- pino from package.json (no longer used outside the moved file)

/add-whatsapp-v2 skill updated to copy setup/groups.ts and register both
groups + whatsapp-auth in setup/index.ts STEPS, install pino@9.6.0 along
with baileys + qrcode.

Verified: build clean, 326 host tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 14:34:16 +03:00
gavrielc a3376c25df docs(channel-skills): rewrite all 13 /add-*-v2 skills for copy-from-channels-branch pattern
Each skill now:
- Pre-flight: checks for file present + import line + dep listed (idempotent)
- git fetch origin channels
- git show origin/channels:<paths> > <paths> to copy adapter (and helpers/tests/setup-step where applicable)
- Append `import './<chan>.js';` to src/channels/index.ts
- pnpm install <pkg>@<pinned-version>
- pnpm run build

Telegram additionally copies 4 helper/test files + setup/pair-telegram.ts
and registers `'pair-telegram':` in setup/index.ts STEPS.

WhatsApp (native) additionally copies setup/whatsapp-auth.ts and
registers `'whatsapp-auth':` in setup/index.ts STEPS, installs
@whiskeysockets/baileys + qrcode + @types/qrcode pinned.

All credential / next-steps / channel-info / troubleshooting sections
preserved verbatim.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 14:24:20 +03:00
gavrielc 32a973f1cd docs(add-opencode): rewrite skill for copy-from-providers-branch pattern
v2 no longer ships opencode on trunk. The skill now:
- Fetches origin/providers
- Copies opencode source files to their target paths
- Appends self-registration imports to both provider barrels
- Adds @opencode-ai/sdk@1.4.3 as a pinned agent-runner dep
- Adds OPENCODE_VERSION ARG + opencode-ai pnpm global install to Dockerfile
- Rebuilds host + container

All steps idempotent. Credential/env/Zen docs unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 14:14:10 +03:00
Tal Moskovich c9dd6e050e docs: update OpenCode Zen integration details in SKILL.md
- Clarified the use of `x-api-key` for Zen's HTTP API, addressing common issues with Bearer tokens.
- Added configuration examples for `.env` and OneCLI registration for Zen keys.
- Provided guidance on naming conventions for OpenCode agent and provider settings.
- Included a note on the difference in authentication methods between OpenCode and OpenRouter.
2026-04-17 12:20:22 +03:00
Tal Moskovich 22150261c5 feat(v2): OpenCode agent provider
- Add OpenCodeProvider (SSE, session resume, MCP via mcp-to-opencode)
- Register opencode in factory; AGENT_PROVIDER passthrough from DB
- Host: XDG mount, NO_PROXY merge, OPENCODE_* env for opencode sessions
- Dockerfile: opencode-ai CLI; docs checklist + architecture diagram
- Skill add-opencode for v2; AgentProviderName in src/types.ts

Made-with: Cursor
2026-04-17 12:20:22 +03:00
gavrielc f04921deee docs(v2): runtime-split guide, CLAUDE.md gotchas, setup CJK autodetect
- docs/v2-build-and-runtime.md: new — runtime split rationale (Node host,
  Bun container), lockfile topology, supply-chain trade-offs, image build
  surface, two session-wake paths, CI shape, key invariants. Indexed from
  CLAUDE.md v2 Docs Index.
- CLAUDE.md: Container Runtime (Bun) section with trigger/action gotchas
  a contributor editing the container must know (named-param prefix rule,
  bun:test vs vitest, bun.lock regeneration, no minimumReleaseAge for the
  Bun tree, no tsc build step, DELETE pragma invariant). CJK font support
  section for Claude sessions outside of /setup to proactively offer when
  they detect CJK signals. Development section updated with Bun commands.
- .claude/skills/setup/SKILL.md: step 3b — auto-enable CJK fonts without
  asking if the user is already writing in CJK; otherwise ask only on clear
  signals (CJK timezone from step 2a). 3c renumbered from old 3b.
2026-04-17 11:38:20 +03:00
gavrielc 22498ae69c fix: remaining npm→pnpm gaps + dockerignore for pnpm symlinks
- container/.dockerignore (new): exclude agent-runner/node_modules and
  agent-runner/dist so COPY agent-runner/ ./ doesn't clobber the
  pnpm-installed node_modules with host directories. Under npm's flat
  layout this was forgiving; under pnpm's symlink layout it's a hard
  conflict (overlay2 cannot copy onto a symlink target).
- setup/{groups,service}.ts: execSync('pnpm run build') not npm.
- setup/index.ts: usage string.
- scripts/*.ts: usage comments + seed-discord final log.
- .claude/settings.json: permission allowlist entries.
- .claude/skills/{add-whatsapp-v2,add-dashboard}/SKILL.md: docs.
- container/skills/{frontend-engineer,vercel-cli,self-customize}/SKILL.md:
  agent-facing docs still told the container agent to run npm.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 09:53:00 +03:00
gavrielc 504e5296c9 fix: pnpm-lock sync, per-group build-script allowlist, ppnpm typos
- Regenerate pnpm-lock.yaml to match v2 package.json (Baileys 6.17.16,
  @chat-adapter/linear 4.26.0)
- src/container-runner.ts: when install_packages rebuilds a per-group
  image, append each installed package to /root/.npmrc's
  only-built-dependencies before pnpm install -g, so packages with
  postinstall scripts (playwright, puppeteer, native addons) don't
  install silently broken
- Fix stray 'ppnpm uninstall' in 13 skill files (REMOVE.md + SKILL.md)
  left over from the npm→pnpm sed pass

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 09:25:59 +03:00
meeech 211d2b5877 docs: convert all skill instructions from npm to pnpm
Batch update 62 files across .claude/skills/ — SKILL.md, REMOVE.md,
and script files. Conversions: npm run -> pnpm run, npm install ->
pnpm install, npx -> pnpm exec/dlx, npm uninstall -> pnpm uninstall,
package-lock.json -> pnpm-lock.yaml, shebangs updated.
2026-04-17 09:22:45 +03:00
Gabi Simons 1aeb8fb4ca refactor(add-vercel): drop Frontend Engineer delegation, add pre-deploy checks
The specialist-subagent pattern forced every /add-vercel user through the
OneCLI credential-assignment plumbing (dynamically created Frontend Engineer
agents had no Vercel secret on first deploy). For a personal assistant the
isolation wasn't worth the complexity — the host agent can deploy to Vercel
directly using the same CLI.

- Remove the Phase 5 CLAUDE.md patch that forbade writing frontend code
- Drop the bundled frontend-engineer container skill
- Strip the HARD RULE + "Building Websites" delegation from vercel-cli
- Add a concise "Pre-Send Checks" section: local build, deployment READY,
  live URL returns 2xx, optional agent-browser visual check

Net: -194 lines. /add-vercel now installs the CLI, registers the secret,
assigns it to existing agents, and teaches the agent to verify before
sharing the URL. No subagent plumbing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 19:59:30 +00:00
gavrielc cc784ff94b refactor(v2): remove trigger_credential_collection MCP tool
Drops the in-chat credential-collection flow introduced in e92b245. Agents
can no longer collect API keys via a secure modal — users must add secrets
through OneCLI directly. Keeps the OneCLI manual-approval handler and
threaded-routing work from the same commit intact.

Removed:
* container/agent-runner/src/mcp-tools/credentials.ts (MCP tool)
* src/credentials.ts (host-side modal/OneCLI pipeline)
* src/db/credentials.ts + migration 005 (pending_credentials table)
* src/onecli-secrets.ts (createSecret CLI facade, only caller was credentials.ts)
* findCredentialResponse from agent-runner DB layer
* PendingCredential types
* Four credential hooks from ChannelSetup (getCredentialForModal,
  onCredentialReject, onCredentialSubmit, onCredentialChannelUnsupported)
* Credential card/modal handling in chat-sdk-bridge (nccr/nccm prefixes,
  Modal/TextInput imports)
* credential_request text fallback in WhatsApp adapter
* request_credential system-action case in delivery.ts

Added:
* Migration 009 drops pending_credentials on existing installs.

Vercel skill now tells the agent to ask the user to register the token via
OneCLI instead of invoking the removed tool.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 21:41:41 +03:00
gavrielc e55ed0f4e8 fix(whatsapp): upgrade Baileys 6.7→6.17, fix proto import and 515 restart
Baileys 6.7.21 silently failed the pairing handshake. Upgrade to 6.17.16
which fixes this. Three related issues:

1. proto is no longer a named ESM export in 6.17.x — use createRequire
   to import via CJS (matching the proven v1 pattern).
2. Setup auth script didn't handle the 515 stream restart that WhatsApp
   sends after successful pairing. Refactored to reconnect (matching v1's
   connectSocket(isReconnect) pattern) instead of hanging until timeout.
3. Added succeeded guard and process.exit(0) to prevent timeout race
   after successful auth.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 21:01:55 +03:00
gabi-simons 82422d2077 fix(vercel): complete add-vercel flow for fresh installs
- Add Phase 5: patch agent CLAUDE.md with frontend delegation rule
  so agents treat it as a hard constraint, not a suggestion
- Add Phase 6: sync container skills to existing agent sessions
  (skills are copied once at group creation, not auto-updated)
- Add OneCLI secret assignment step in Phase 3 (selective mode
  requires explicit assignment per agent)
- Add hard rule to vercel-cli container skill header
- Clean up Phase 4 (check Dockerfile before rebuilding)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 15:36:06 +00:00
gavrielc 4ae9785a61 fix(setup): move OpenClaw detection into environment step
Avoids running `ls -d ~/.openclaw` as a separate Bash command which
triggers permission prompts for reading outside the project directory.
The environment step now reports OPENCLAW_PATH in its status block.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 14:14:25 +03:00
gavrielc 79fd142be4 improve setup UX: welcome message + AskUserQuestion for pre-approval
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 14:06:37 +03:00
gavrielc ce80e4ec3e feat(setup): add Linear channel, fix setup permissions
Enable Linear channel adapter. Fix setup permission rules: use specific
npm install entries per adapter package, replace cp -r with rsync -a to
avoid built-in cp safety prompt, add head to allow list for chained
commands. Update Linear API key URL.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 14:00:27 +03:00
gavrielc 57c9bfc670 improve setup flow: streamline steps, add pre-approval, new manage-mounts skill
- Disable sandbox by default in project settings
- Setup: remove Apple Container option (Docker only), single channel selection
  with plain text list, move fork to end, auto-set empty mounts, add command
  pre-approval step, add UTC timezone confirmation, add wait-on-user guidance,
  add 5m timeouts for long steps
- iMessage: improve Full Disk Access UX with Finder open + drag instructions
- Add /manage-mounts skill for post-setup mount configuration
- Enable iMessage channel import

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 11:26:20 +03:00
Gabi Simons c54c779834 feat(v2/add-vercel): add frontend-engineer skill with agent delegation
When /add-vercel is applied, agents that need to build websites spin up
a dedicated Frontend Engineer agent instead of building inline. The
frontend agent enforces build-test-verify discipline with visual browser
verification before deploying to Vercel.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 13:44:27 +00:00
Gabi Simons e9a427ad1a docs(v2): add /add-dashboard skill with resource-based pusher
Self-contained skill: SKILL.md has instructions, resources/ holds
the dashboard-pusher.ts that gets copied to src/ at install time.
No src/ changes until the skill is applied.

npm package: @nanoco/nanoclaw-dashboard
Repo: https://github.com/qwibitai/nanoclaw-dashboard

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 13:21:19 +00:00
Koshkoshinsk 77321984ba feat(pair-telegram): emit REMINDER_TO_ASSISTANT in status block
Move the "print the pairing code as plain text" directive from three
skill docs into the CLI output itself. Every caller of pair-telegram
(init-first-agent, manage-channels, add-telegram-v2, future callers)
now sees the reminder directly in the PAIR_TELEGRAM_ISSUED and
PAIR_TELEGRAM_NEW_CODE blocks. Skill docs shortened to point at it.

Also add a short pre-tool-call sentence in init-first-agent step 3b
instructing the assistant to extract the code and ask the user to send
it in Telegram.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 11:50:25 +00:00
Koshkoshinsk 1eaf4f88d9 Revert "docs(skills): print pairing code as final message; drop log-tail verify"
This reverts commit bd6a26a002.
2026-04-15 10:48:17 +00:00
Koshkoshinsk bd6a26a002 docs(skills): print pairing code as final message; drop log-tail verify
- Reword pair-code instruction across add-telegram-v2, manage-channels,
  and init-first-agent so the very last user-visible message after
  generating the code MUST be a plain-text print of it.
- Replace init-first-agent's tail -f based verify step with a plain-text
  prompt asking the user to confirm receipt of the welcome DM, falling
  back to DB-based diagnostics only on non-arrival. Avoids harness
  blocks on long leading sleeps and fragile log-string greps.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 10:31:46 +00:00
Koshkoshinsk 6801a14736 docs(skills): require pairing code be printed as final user-visible message
Claude Code's UI collapses bash tool output, so the user never sees the
pairing code emitted by pair-telegram. Reframe the skill instructions
to require the last user-visible message at this step to be a plain-text
print of the code.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 10:06:58 +00:00
Koshkoshinsk f60b42666f docs(skills): surface telegram pairing code outside bash output
Claude Code's UI folds bash tool results by default, hiding the 4-digit
pairing code from the user. Instruct the skill to echo the CODE as plain
text in the reply so it's always visible.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 08:42:39 +00:00
gavrielc 0d3326aae5 feat(v2): user-level privilege model + cold DM infra + init-first-agent skill
Replaces the agent-group-centric "main group" concept with user-level
privileges and adds the cold-DM infrastructure needed for proactive
outbound messaging (pairing, approvals, welcome flows).

Privilege model
- New tables: users, user_roles (owner global-only; admin global or
  scoped to an agent_group), agent_group_members (explicit non-
  privileged access; admin/owner imply membership), user_dms (cold-DM
  resolution cache).
- Removed agent_groups.is_admin, messaging_groups.admin_user_id. Replaced
  with messaging_groups.unknown_sender_policy (strict | request_approval
  | public) for per-chat unknown-sender gating.
- src/access.ts: canAccessAgentGroup, pickApprover, pickApprovalDelivery.
- src/router.ts: access gate on every inbound, honoring
  unknown_sender_policy for unknown senders.
- src/channels/telegram.ts: pairing interceptor upserts the paired user
  and promotes them to owner if hasAnyOwner() is false (first-pair-wins).

Cold DM infrastructure
- ChannelAdapter.openDM?(handle) — optional method. Chat-SDK-bridge wires
  it to chat.openDM() for resolution-required channels (Discord, Slack,
  Teams, Webex, gChat); direct-addressable channels (Telegram, WhatsApp,
  iMessage, Matrix, Resend) fall through to the handle directly.
- src/user-dm.ts: ensureUserDm(userId) — resolves + caches via user_dms.

Approval routing
- onecli-approvals + delivery use pickApprover + pickApprovalDelivery:
  scoped admins → global admins → owners (dedup), first reachable via
  ensureUserDm, same-channel-kind tie-break. Approvals land in the
  approver's DM, not the origin chat.

Delivery fixes
- delivery.ts ACL rejection now throws instead of returning undefined —
  the outer loop previously marked rejected messages as delivered.
- Implicit-origin allow: session.messaging_group_id === target skips the
  destination check.
- createMessagingGroupAgent auto-creates the companion agent_destinations
  row (normalized local_name from the messaging group's name, collision-
  broken within the agent's namespace).

Container
- container-runner.ts: /workspace/global always read-only; drops
  NANOCLAW_IS_ADMIN; adds NANOCLAW_ADMIN_USER_IDS (owners + global admins
  + scoped admins for this agent group). Agent-runner poll-loop gates
  slash commands against that set.

New skill: /init-first-agent
- Walks the operator through standing up the first agent for a channel:
  channel pick → identity lookup (reads each channel SKILL.md's
  ## Channel Info > how-to-find-id) → DM platform_id resolution (direct-
  addressable, cold-DM via "user DMs bot first + sqlite lookup", or
  Telegram pair-code fallback) → run scripts/init-first-agent.ts →
  verify via tail of nanoclaw.log.
- scripts/init-first-agent.ts: parameterized helper that upserts the
  user + grants owner (if none), creates dm-with-<display-name> agent
  group + initGroupFilesystem, reuses/creates the DM messaging_group,
  wires it (auto-creates destination), resolves the session, and writes
  a kind:'chat' / sender:'system' welcome message into inbound.db. Host
  sweep wakes the container and the agent DMs the operator via the
  normal delivery path.

/manage-channels rewrite
- Drops --is-main / --jid / main-vs-non-main isolation references.
- First-channel flow delegates to /init-first-agent.
- Explains createMessagingGroupAgent auto-creates destinations.
- Adds a privileged-users show section.

setup/
- register.ts: drop --is-main, --jid, --local-name, --trigger
  requiresTrigger defaults; call initGroupFilesystem; normalize to
  v2 schema (no is_admin, no admin_user_id, sets unknown_sender_policy
  'strict'); let createMessagingGroupAgent handle the destination row.
- pair-telegram.ts: emit PAIRED_USER_ID (namespaced "telegram:<id>")
  instead of ADMIN_USER_ID; update header comment.
- register.test.ts deleted — was v1-only, tested a registered_groups
  table that no longer exists.

Docs
- v2-architecture-diagram.{md,html}: ER diagram updated to drop
  is_admin/admin_user_id, add unknown_sender_policy, and include
  users/user_roles/agent_group_members/user_dms.
- v2-architecture-draft.md: approval-routing paragraph rewritten for
  pickApprover/pickApprovalDelivery/ensureUserDm; SQL schema block
  updated; admin-verification paragraph references
  NANOCLAW_ADMIN_USER_IDS.
- v2-setup-wiring.md: entity-model sketch rewritten.
- v2-checklist.md: marked privilege refactor / container filtering /
  approval routing / unknown-sender gating done; removed obsolete
  admin_user_id and main-vs-non-main items.

Scripts
- scripts/init-first-agent.ts (new) replaces scripts/welcome-owner-dm.ts
  (removed; welcome-owner was a Discord-specific one-off).
- test-v2-host.ts, test-v2-channel-e2e.ts, seed-discord.ts: drop
  is_admin + admin_user_id, use unknown_sender_policy.

Tests
- src/access.test.ts (new): 14 tests for canAccessAgentGroup, role
  helpers, pickApprover, ensureUserDm, pickApprovalDelivery.
- src/db/db-v2.test.ts: adds 3 tests for the auto-created
  agent_destinations row (normalized name, no duplicates, collision
  break within an agent group).
- host-core.test.ts, channel-registry.test.ts: updated fixtures to
  use unknown_sender_policy: 'public' where the test exercises routing
  rather than the access gate.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 00:03:51 +03:00
Gabi Simons 8d60af71d3 feat(v2): add /add-vercel skill for agent Vercel deployments
Setup skill that installs Vercel CLI in agent containers and configures
OneCLI credential injection for api.vercel.com. Container skill bundled
in .claude/skills/add-vercel/container-skills/ and copied to
container/skills/ during setup. Also adds dashboard & web apps prompt
to /setup flow (step 5b).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 15:24:31 +00:00
Gabi Simons 192a5a7569 docs(v2): add /add-whatsapp-v2 setup skill
Separate from the v1 /add-whatsapp skill — v1 remains untouched.
Follows the v2 skill pattern (flat sections, defers to /manage-channels
for wiring). Covers Baileys auth, pairing code, QR code, and
documents the native adapter's features and limitations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 12:02:27 +00:00
Koshkoshinsk 65afcdc946 feat(telegram-pairing): surface wrong-code attempts + auto-regen with retry cap
- createPairing now replaces any existing pending pairing for the same intent
  (replace-by-default; no "two pending codes for one intent" state)
- tryConsume records each attempt on pending records (capped at 10); a
  wrong code invalidates the pairing immediately (one attempt per code)
- waitForPairing gains onAttempt callback for misses and rejects with a
  distinct "invalidated by wrong code" message so callers can distinguish
  TTL expiry from user-error
- pair-telegram emits PAIR_TELEGRAM_ATTEMPT on misses and auto-regenerates
  the pairing up to 5 times, emitting PAIR_TELEGRAM_NEW_CODE for each
- Skill docs updated so the host Claude knows to show new codes and
  offer another batch on max-regenerations-exceeded

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 12:27:09 +00:00
Koshkoshinsk 2454444f2e feat(telegram-pairing): accept bare 4-digit codes
Require the message to be exactly the 4 digits (optionally prefixed by
@botname). Loose matches like "my pin is 0349" are rejected to avoid false
positives from chat traffic that happens to contain a 4-digit number.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 12:27:06 +00:00
Koshkoshinsk 2017589683 feat(telegram): self-contained pairing for chat ownership verification
BotFather issues bot tokens with no user binding, so anyone who guesses the
bot's username can DM it and get registered as a channel. Pairing closes that
gap: setup issues a one-time 4-digit code, the operator echoes it back from
the chat they want to register, and the inbound interceptor binds
admin_user_id before the message reaches the router.

- src/channels/telegram-pairing.ts: JSON-backed store with createPairing,
  tryConsume, getStatus, waitForPairing (fs.watch + poll fallback)
- src/channels/telegram.ts: wraps bridge.setup with an onInbound interceptor
  that consumes pairing codes and upserts messaging_groups
- setup/pair-telegram.ts: CLI step issues a code and waits up to 5 min for
  the operator to echo it back, emitting PLATFORM_ID/IS_GROUP/ADMIN_USER_ID
- Skill docs: /setup reorders mounts -> service -> wire (pairing needs a
  live polling adapter); /manage-channels and /add-telegram-v2 use pairing
  instead of asking the user to discover chat IDs

All other channels still bind admin via install-time identity (OAuth/QR/token);
pairing is Telegram-only. The bridge, router, and other adapters are untouched.
2026-04-13 12:27:02 +00:00