Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
fc3101a
Merge remote-tracking branch 'upstream/staging'
Apr 14, 2026
b503b0f
Finalize v0.25 runtime upgrade workflow
Apr 15, 2026
20b1e6e
fix(sandbox): mount Docker socket and fix channel broadcast filtering
Apr 15, 2026
6fc61fe
docs(sandbox): update CHANGELOG, v025 upgrade script, and README for …
Apr 15, 2026
49fab9b
chore: merge upstream/staging (ae1f698..427783d) into fork/main
Apr 15, 2026
21ebc12
fix(memory): treat version<=0 as unset, improve schema to prevent LLM…
Apr 16, 2026
2fc8868
fix(telegram): hot-activation owner_id type + 3-level fallback chain
Apr 23, 2026
f8ee5e9
ci: add GHCR auto-publish + Watchtower for hands-off updates
Apr 23, 2026
9f6d8cf
chore(copilot): add VS Code Copilot customization files
Apr 23, 2026
4baeb29
Merge remote-tracking branch 'upstream/staging'
Apr 23, 2026
c679b6f
Merge upstream/main v0.26.0 into fork/main
Apr 23, 2026
ea848b7
docs: add Docker install guide, WSL2 prerequisites, and Upgrading sec…
Apr 23, 2026
7c46329
fix(memory): treat old_string='' as absent, fall through to write mode
Apr 23, 2026
f316b47
fix(docker): strip CRLF from SQL migrations before embed_migrations! …
Apr 23, 2026
e161866
docs(changelog): add unreleased entries for memory_write and CRLF Doc…
Apr 23, 2026
3c1fec2
chore(release): v0.20.1 patch release
Apr 23, 2026
6441b42
docs(changelog): add [0.20.0] section and clear [Unreleased] stale items
Apr 23, 2026
21c521a
fix(telegram): retry deleteWebhook on transient TLS errors at startup
Apr 24, 2026
0ebc1cf
feat(telegram): enable webhook mode by default
Apr 25, 2026
72321a1
chore: sync upstream/staging 2026-04-27 (10 new commits)
github-actions[bot] Apr 27, 2026
4015713
fix ghcr upgrade path and telegram defaults
JZKK720 Apr 28, 2026
c88dbde
Sync upstream main 0.27.0 changes
JZKK720 Apr 30, 2026
7b0606b
Align fork GHCR and release channels
JZKK720 Apr 30, 2026
297b49e
Fix GHCR deployment pull references
JZKK720 Apr 30, 2026
3ba526c
Fix ClawHub registry fallback
JZKK720 Apr 30, 2026
64eb297
Document ClawHub proxy settings for GHCR deploys
JZKK720 Apr 30, 2026
f80ab8f
chore(scripts): add upstream intake evaluator [skip ci]
May 6, 2026
048c220
chore: stabilize docker pull upgrades
May 7, 2026
d392ec0
Merge upstream ironclaw-v0.28.0 into main
May 8, 2026
ca810d0
chore: update WASM artifact SHA256 checksums [skip ci]
github-actions[bot] May 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Database Configuration
DATABASE_BACKEND=postgres # Pin postgres for compose/local server mode; otherwise ~/.ironclaw/ironclaw.db can auto-select libsql
DATABASE_URL=postgres://localhost/ironclaw
DATABASE_POOL_SIZE=30 # multi-tenant default; reduce to 5-10 for single-user or low-resource deployments

Expand Down Expand Up @@ -195,6 +196,12 @@ HEARTBEAT_INTERVAL_SECS=1800
HEARTBEAT_NOTIFY_CHANNEL=cli
HEARTBEAT_NOTIFY_USER=default

# Local IronClaw home directory mounted into Docker when using docker-compose.yml.
# Set this to ~/.ironclaw to reuse an existing host home; leave unset to use repo-local state.
# IRONCLAW_HOME_DIR=~/.ironclaw
# Docker Compose stores recent local history in the external Docker volume `ironclaw-pgdata`.
# Create it once with: docker volume create ironclaw-pgdata

# Memory hygiene settings (automatic cleanup of stale workspace documents)
# Runs on each heartbeat tick; discovers cleanup targets from .config metadata
# MEMORY_HYGIENE_ENABLED=true
Expand Down
3 changes: 2 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
tests/test-pages/**/*.html linguist-generated=true
tests/test-pages/**/*.html linguist-generated=true
migrations/*.sql text eol=lf
77 changes: 77 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# IronClaw — Copilot Instructions

IronClaw is a secure, self-expanding personal AI assistant written in Rust (tokio async, axum, wasmtime). See [AGENTS.md](../AGENTS.md) for the authoritative agent contract and [CLAUDE.md](../CLAUDE.md) for the full development guide.

## Build & Test

```bash
cargo fmt
cargo clippy --all --benches --tests --examples --all-features # zero warnings required
cargo test # unit tests
cargo test --features integration # + PostgreSQL tests
RUST_LOG=ironclaw=debug cargo run # run with logging
```

**Windows — Smart App Control blocks freshly compiled binaries.** Use Docker as the authoritative build path:
```powershell
docker compose up -d --build ironclaw
```

## Docker Build Modes

- For deploy-like validation, stay in pull mode: `docker compose pull` and then `docker compose up -d --no-build postgres ironclaw`.
- `ironclaw-worker` is still a required runtime image for orchestrated job containers, but its compose service is build-only; do not start it with `docker compose up` unless you are explicitly testing that image build.
- Engine v2 `/project/` sandboxing is a different container path driven by [crates/Dockerfile.sandbox](../crates/Dockerfile.sandbox) and [docs/plans/2026-04-10-engine-v2-sandbox.md](../docs/plans/2026-04-10-engine-v2-sandbox.md). Do not remove `Dockerfile.worker` or the `SANDBOX_IMAGE` path without first auditing [src/config/sandbox.rs](../src/config/sandbox.rs), [src/orchestrator/job_manager.rs](../src/orchestrator/job_manager.rs), [src/cli/mod.rs](../src/cli/mod.rs), and [src/bridge/sandbox/](../src/bridge/sandbox/).
- For pull-based local rollouts, treat `.env`, `IRONCLAW_HOME_DIR`, and the external `ironclaw-pgdata` volume as operator-owned state. Back them up before `docker compose pull` or container recreation.

## Non-Negotiable Invariants

| Rule | Scope |
|------|-------|
| No `.unwrap()` / `.expect()` in production code | All `src/` |
| Zero clippy warnings — fix before committing | All changes |
| All mutations from handlers/CLI go through `ToolDispatcher::dispatch()` | Handlers, CLI, channels |
| New DB features must support both PostgreSQL **and** libSQL | `src/db/`, `migrations/` |
| Check `FEATURE_PARITY.md` when any tracked behavior changes | All PRs |
| Regression test with every bug fix | All PRs |
| Use `crate::` for cross-module imports, `super::` only intra-module | All `src/` |

## Module Specs (read before touching a subsystem)

| Subsystem | Spec |
|-----------|------|
| `src/agent/` | [src/agent/CLAUDE.md](../src/agent/CLAUDE.md) |
| `src/channels/web/` | [src/channels/web/CLAUDE.md](../src/channels/web/CLAUDE.md) |
| `src/db/` | [src/db/CLAUDE.md](../src/db/CLAUDE.md) |
| `src/llm/` | [src/llm/CLAUDE.md](../src/llm/CLAUDE.md) |
| `src/tools/` | [src/tools/README.md](../src/tools/README.md) |
| `src/workspace/` | [src/workspace/README.md](../src/workspace/README.md) |
| `crates/ironclaw_engine/` | [crates/ironclaw_engine/CLAUDE.md](../crates/ironclaw_engine/CLAUDE.md) |

## Extracted Crates

Safety logic lives in `crates/ironclaw_safety/`; skills in `crates/ironclaw_skills/`. Import directly — `src/safety/mod.rs` and `src/skills/mod.rs` are thin shims that no longer glob-re-export. Use `use ironclaw_safety::SafetyLayer` not `crate::safety::SafetyLayer`.

## Subsystem Rules (auto-applied by file pattern)

Detailed rules live in [.claude/rules/](../.claude/rules/) and are surfaced as VS Code instructions:

- [database.instructions.md](instructions/database.instructions.md) → `src/db/**`, `migrations/**`
- [testing.instructions.md](instructions/testing.instructions.md) → `src/**/*.rs`, `tests/**`
- [tools-and-dispatch.instructions.md](instructions/tools-and-dispatch.instructions.md) → `src/tools/**`, `src/channels/**`, `src/cli/**`
- [safety-and-sandbox.instructions.md](instructions/safety-and-sandbox.instructions.md) → `src/safety/**`, `src/sandbox/**`, `src/secrets/**`
- [ci-cd.instructions.md](instructions/ci-cd.instructions.md) → `.github/workflows/**`, `Dockerfile*`, `docker-compose.yml`
- [local-ops.instructions.md](instructions/local-ops.instructions.md) → `docker-compose.yml`, `.env`, `README.md`, `deploy/**`, `docs/drafts/install/**`, `docs/drafts/platforms/**`
- [telegram-channel.instructions.md](instructions/telegram-channel.instructions.md) → `channels-src/telegram/**`

## Useful Prompts

| Prompt | Purpose |
|--------|---------|
| `/smoke-test-telegram` | Smoke-test the Telegram WASM channel end-to-end |
| `/check-pr-ready` | Run the pre-commit discipline checklist before opening a PR |
| `/sync-upstream` | Step-by-step guide to manually merge upstream/main into fork/main |
| `/validate-ghcr-upgrade` | Audit whether upstream changes are safe to publish to fork GHCR and whether downstream update/install channels will actually pick them up |
| `/validate-installer-release-channel` | Audit whether PowerShell, shell, MSI, cargo-dist releases, and embedded registry URLs actually resolve to the fork-owned release channel |
| `/update-local-docker-runtime` | Backup-first guide to pull new GHCR images into the local Docker stack without losing `.env`, bind-mounted state, or the external Postgres volume |
| `/add-wasm-channel` | Scaffold a new WASM channel from scratch |
61 changes: 61 additions & 0 deletions .github/instructions/ci-cd.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
applyTo: ".github/workflows/**,docker-compose.yml,Dockerfile,Dockerfile.worker,Dockerfile.test"
description: "CI/CD, Docker, and build rules for IronClaw. Apply when editing GitHub Actions workflows, docker-compose.yml, or Dockerfiles."
---

# CI/CD & Build Rules

## Windows — Smart App Control

**On Windows, Smart App Control blocks freshly compiled Rust binaries.** Docker is the only viable build and test path on Windows:

```powershell
docker compose up -d --build ironclaw # build + run
docker compose exec ironclaw cargo test # run tests inside container
```

Never attempt `cargo run` or `cargo test` directly on Windows hosts in this repo.

## GitHub Actions Workflows

| Workflow | Trigger | Purpose |
|----------|---------|---------|
| `docker-publish.yml` | Push to `main` | Build + push `ironclaw` and `ironclaw-worker` to GHCR |
| `sync-upstream.yml` | Weekly Mon 02:00 UTC + manual | Auto-merge `upstream/main` → `fork/main`; builds GHCR images inline |
| `test.yml` | Push, PR | Cargo unit tests |
| `staging-ci.yml` | Push to `staging` | Full integration test suite |
| `claude-review.yml` | PR | Automated code review |

## GHCR Image Names

```
ghcr.io/jzkk720/ironclaw:latest # main runtime (target: runtime-staging)
ghcr.io/jzkk720/ironclaw-worker:latest # sandbox worker
```

The moving auto-update tag is `:latest`; workflows may also publish immutable `:sha-*` tags for traceability.

## Dockerfile Build Targets

| Target stage | Used for |
|-------------|---------|
| `runtime-staging` | Production image (used by `docker-publish.yml`) |
| `runtime` | Base runtime without staging extras |
| `builder` | Intermediate — do not use as final image |

## sync-upstream Mechanics

**GITHUB_TOKEN pushes do not re-trigger other workflows.** This is why `sync-upstream.yml` builds and pushes Docker images inline rather than relying on `docker-publish.yml` triggering after its push. If you add build steps to one workflow, check whether the other needs to be updated too.

## Watchtower

Watchtower is defined in `docker-compose.yml` and polls GHCR hourly. It only updates containers with label `com.centurylinklabs.watchtower.enable: "true"`. The `ironclaw` service has this label; `postgres` and others do not.

**One-time host prerequisite** (already documented in docker-compose.yml):
```bash
docker login ghcr.io -u jzkk720 -p <PAT with read:packages>
```

## Concurrency

Both `docker-publish.yml` and `sync-upstream.yml` use concurrency groups to prevent parallel builds of the same branch. `docker-publish.yml` cancels in-progress builds; `sync-upstream.yml` does not (to avoid skipping a sync).
46 changes: 46 additions & 0 deletions .github/instructions/database.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
applyTo: "src/db/**,src/history/**,migrations/**"
description: "Database rules for IronClaw dual-backend persistence (PostgreSQL + libSQL). Apply when editing db/, history/, or migration files."
---

# Database Rules

Full rules: [.claude/rules/database.md](../../.claude/rules/database.md)

**All new persistence features must support both PostgreSQL and libSQL.** See [src/db/CLAUDE.md](../../src/db/CLAUDE.md).

## Adding a New Operation

1. Add the async method to the relevant sub-trait in `src/db/mod.rs`
2. Implement in `src/db/postgres.rs`
3. Implement in `src/db/libsql/<module>.rs` (use `self.connect().await?` per operation)
4. Add migration if needed:
- PostgreSQL: new `migrations/VN__description.sql`
- libSQL: entry in `INCREMENTAL_MIGRATIONS` in `libsql_migrations.rs`
- **Version numbering**: always number after the highest version on `staging`/`main` — check with `git ls-tree origin/staging migrations/`
5. Verify dual compilation:
```bash
cargo check # postgres (default)
cargo check --no-default-features --features libsql # libsql only
cargo check --all-features # both
```

## SQL Dialect Quick Reference

| PostgreSQL | libSQL |
|-----------|--------|
| `UUID` | `TEXT` |
| `TIMESTAMPTZ` | `TEXT` (ISO-8601, use `fmt_ts()` / `get_ts()`) |
| `JSONB` | `TEXT` (JSON string) |
| `BOOLEAN` | `INTEGER` (0/1, read with `get_i64(row, idx) != 0`) |
| `NUMERIC` | `TEXT` (rust_decimal) |
| `TEXT[]` | `TEXT` (JSON array) |
| `VECTOR` | `BLOB` (brute-force search fallback) |
| `jsonb_set(col, '{key}', val)` | `json_patch(col, '{"key": val}')` |
| `DEFAULT NOW()` | `DEFAULT (datetime('now'))` |

## Key Rules

- Multi-step operations (INSERT+INSERT, UPDATE+DELETE, read-modify-write) **MUST** be wrapped in a transaction
- `LibSqlBackend::connect()` creates a fresh connection per operation — never hold across `await` points
- Schema translation is more than DDL: check indexes, seed data (`INSERT INTO`), and triggers
42 changes: 42 additions & 0 deletions .github/instructions/local-ops.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
applyTo: "docker-compose.yml,.env,README.md,deploy/**,docs/drafts/install/**,docs/drafts/platforms/**"
description: "Local Docker rollout and state-safety rules for IronClaw. Apply when working on docker compose pull/recreate flows, local container updates, backup or rollback docs, runtime image pins, or operator-owned state such as .env, IRONCLAW_HOME_DIR, and the external Postgres volume."
---

# Local Ops Rules

## Protected State

- Treat `.env`, `IRONCLAW_HOME_DIR`, the repo-local `extensions/ironclaw-home` fallback, and the external `ironclaw-pgdata` volume as operator-owned state.
- Never overwrite, delete, or rotate secrets in `.env` as part of a normal upgrade.
- Never use `docker compose down -v` or remove named volumes during a routine local update unless the user explicitly asks for destructive cleanup.

## Preferred Rollout Modes

- For local upgrades to already-published images, prefer pull mode: `docker compose pull` followed by `docker compose up -d --no-build postgres ironclaw`.
- Pull the worker image as well when runtime and sandbox versions must stay aligned, even though the `ironclaw-worker` compose service is build-only.
- Use `docker compose up -d --build ironclaw` only when validating unpublished source changes instead of a GHCR rollout.
- Respect `IRONCLAW_APP_IMAGE` and `SANDBOX_IMAGE` pins in `.env`. Do not silently switch users from a pinned tag or digest back to `:latest`.

## Preflight Checks

- Capture the current runtime before changing anything: `docker compose ps`, `docker compose images`, and `docker compose config`.
- Verify the running gateway before and after rollout with `http://127.0.0.1:3231/api/health`.
- When upstream code changed, validate GHCR and release-channel safety before instructing operators to pull new images.

## Backup and Rollback Discipline

- Back up `.env` before any pull or recreate step, but never print secret values in logs or chat.
- Dump PostgreSQL with `pg_dump` before recreating containers when data recovery matters.
- Back up the directory referenced by `IRONCLAW_HOME_DIR`; if that variable is unset, back up `extensions/ironclaw-home` instead.
- Record the current image tags or digests before pulling replacements so rollback can repin the previous known-good runtime.
- Restore the database only when a migration or data regression requires it; routine app rollbacks should start by repinning images and restoring bind-mounted state.

## Windows

- On Windows, do not recommend host `cargo` commands for rollout validation. Use Docker-based checks instead.

## Related Guidance

- Use `/validate-ghcr-upgrade` when the question is whether a new fork image is safe to publish or consume.
- Use `/update-local-docker-runtime` for the full backup-first local rollout checklist.
50 changes: 50 additions & 0 deletions .github/instructions/safety-and-sandbox.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
applyTo: "src/safety/**,src/sandbox/**,src/secrets/**,src/tools/wasm/**,crates/ironclaw_safety/**"
description: "Safety, sandbox, and secrets rules for IronClaw. Apply when working in safety/, sandbox/, secrets/, WASM tool sandbox, or the ironclaw_safety crate."
---

# Safety Layer & Sandbox Rules

Full rules: [.claude/rules/safety-and-sandbox.md](../../.claude/rules/safety-and-sandbox.md)

## Safety Layer Pipeline

All external tool output passes through `SafetyLayer` in `crates/ironclaw_safety/`:

1. **Sanitizer** — detects injection patterns, escapes dangerous content
2. **Validator** — checks length, encoding, forbidden patterns
3. **Policy** — rules with severity (Critical/High/Medium/Low) and actions (Block/Warn/Review/Sanitize)
4. **Leak Detector** — scans for 15+ secret patterns at two points: tool output before LLM, and LLM responses before user

Tool outputs are wrapped in `<tool_output>` XML before reaching the LLM.

## Import Convention

Import from the extracted crate directly — **not** from `crate::safety`:
```rust
use ironclaw_safety::SafetyLayer; // correct
use crate::safety::SafetyLayer; // wrong — shim no longer re-exports
```

## Sandbox Policies

| Policy | Filesystem | Network |
|--------|-----------|---------|
| `ReadOnly` | Read-only workspace | Allowlisted domains |
| `WorkspaceWrite` | Read-write workspace | Allowlisted domains |
| `FullAccess` | Full filesystem (host) | Unrestricted |

`FullAccess` requires a second opt-in (`SANDBOX_ALLOW_FULL_ACCESS=true`) and bypasses Docker entirely. Without it, `FullAccess` is silently downgraded to `WorkspaceWrite`.

## Zero-Exposure Credential Model

Secrets are AES-256-GCM encrypted on the host. The sandbox network proxy injects credentials into HTTP requests at transit time. **Container processes never see raw credential values.** Do not pass secrets via env vars into containers — use the proxy allowlist + credential injection path.

## Security Review Checklist

When touching listeners, routes, auth, secrets, sandboxing, approvals, or outbound HTTP:
- [ ] No weakening of bearer-token auth, webhook auth, CORS/origin checks
- [ ] Body limits and rate limits preserved
- [ ] Docker containers treated as untrusted
- [ ] Tool parameters with `sensitive_params()` are redacted before logging
- [ ] No new direct DB calls that bypass the safety/audit pipeline
Loading