- landing/app/mira/wiki: tag=mira-wiki list now shows all wiki paragraphs
(depends on KBDB tag filter exposed in matrix/kbdb commit, separate repo)
- landing: app/mira hub + feed split + various WIP from prior sessions
- registry/components: claude_api / kbdb_create_block / kbdb_get / km_writer /
platform_crypto / auth_oauth2 contracts + main.go (accumulated)
- .component-builds: pkg-lock updates + index.ts adjustments (WIP)
- .agents/specs/arcrun/frontend-redesign: design notes
- docs/test_credentials, docs/user_requirements/arcrun-landing-page: WIP docs
- cypher-executor: auth-dispatcher / wasi-shim adjustments (WIP)
Includes accumulated work from prior sessions plus the wiki UI tag-filter
update that surfaces the AI-generated wiki paragraphs at /mira/wiki.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Three platform-level improvements that together enable the full
"草稿 → LLM 整理 → KBDB" wiki ingest workflow via cypher binding:
## 1. Nested interpolation in node.data
Previously {{var}} only supported top-level keys, so {{item.content}}
literal-passed through. Now supports dot-path:
{{paragraph.content}} → ctx.paragraph.content
{{paragraphs.0.entity}} → ctx.paragraphs[0].entity
Non-string values (object/array) JSON.stringify automatically.
## 2. 對每個 X cypher binding syntax
'A >> 對每個 paragraph >> B' parses into FOREACH edge with
iterator='paragraph'. graph-builder.ts strips the iterator from label
before edge type resolution. Backwards compatible: bare '對每個' still
defaults to item.
## 3. FOREACH preserves outer context
itemContext was previously {...result, [iter]: item}, dropping
top-level api_key etc. Now {...outerCtx, ...result, [iter]: item} so
{{api_key}} interpolation works in foreach body.
## 4. Unified recipe output parsing (sync + resume)
Extracted parseRecipeOutput() helper used by both sync claude_api
result + workflow resume callback. Strips ```json fence, parses,
spreads parsed top-level fields into result so downstream FOREACH
finds 'paragraphs' (not buried in data.paragraphs).
paused state now stores recipe_output_format + required_fields so
resume route can apply same parsing as sync path.
End-to-end verified:
- input(草稿+api_key) → synth(claude_api+recipe) → 對每個 paragraph → write_wiki(kbdb_create_block)
- Real Claude synthesis on Mira daemon: 3 triplets + 2 paragraphs
- Both paragraphs written to KBDB as wiki-page blocks (verified GET)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
WebAssembly memory can grow (and return a new ArrayBuffer) during an
async host function call. Reading memory.buffer before await and using
it after the await causes host functions (kv_get / crypto_decrypt /
crypto_sign_rs256 / http_request) to write into a detached buffer,
so the WASM side reads zero bytes → empty string → JSON parse failure.
Fix: read inputs before await using the current buffer snapshot,
then call memory.buffer again after the await to write the result.
For crypto_sign_rs256 and http_request, input arrays are copied
before await so the snapshot can be released.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tier2 deploy failed with ERR_PNPM_RECURSIVE_EXEC_FIRST_FAIL
because cypher-executor / registry / builtins package.json
didn't list wrangler; local dev worked via global install only.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
setup-node's cache: 'pnpm' requires the cache-dependency-path to
resolve, but several legacy .component-builds/* Workers only ship
package-lock.json (historical mixed state — see rule
05-deploy-convention.md). With pnpm-lock.yaml missing, setup-node
fails fast with "Some specified paths were not resolved" before
the install step's fallback logic even gets a chance to run.
Since each Worker deploy takes ~30s on its own runner, skipping
the per-job cache costs nothing in practice.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
fetch-depth: 2 is too shallow — a batch push of 10 commits (like
Phase 1-6 commit chain) leaves github.event.before outside the
fetched range, so git diff returns empty and nothing deploys.
- Set fetch-depth: 0 (full history) so diff always has a reachable
base.
- Added git cat-file -e check: even with full history, force-pushes
or orphan base SHAs trigger a "deploy all" fallback instead of
silently skipping.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- landing/: Next.js 15 app for arcrun.dev (dashboard, integrations,
API docs, login). Deploys via Cloudflare Pages — CI scan skips
this via pages_build_output_dir marker.
- builtins/: minimal Hono Worker at arcrun-builtins (/init for
one-shot component registry seeding). initComponents logic is
flagged stale in src/index.ts for future rewrite.
- BETA_TEST.md: pre-launch validation playbook.
- README.md: updated to match current arcrun.dev / acr CLI flow.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Rewrites deploy.yml to auto-discover every wrangler.toml in the repo
(excluding node_modules and Pages projects) rather than hardcoding
each Worker. Adding a new Worker only requires the new directory —
no workflow changes.
- Two-tier fanout: tier1 = .component-builds/* (WASM rebuild +
deploy in parallel), tier2 = orchestration Workers (cypher-executor,
registry, builtins) that depend on tier1 via service bindings.
- Diff-aware on push: only changed Worker dirs deploy; changes under
registry/components/{name}/ cascade to .component-builds/{name}/.
- workflow_dispatch inputs: force_all (deploy everything) and only
(comma-separated allow-list).
- TinyGo 0.40.1 rebuilds WASM from registry/components/{name}/main.go
so deployed binaries always match source.
- max-parallel: 5 to stay under Workers API rate limit.
Adds .claude/rules/05-deploy-convention.md documenting the
"new Worker = new dir + wrangler.toml" invariant.
Per .agents/specs/arcrun/credential-primitives-wasm Phase 6.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- New: acr recipe (push/list/get a user recipe to RECIPES KV)
- New: acr auth-recipe (inspect platform-seeded auth recipes)
- push/creds/init/parts/config updated to match the new cypher-executor
routing (/auth, /credentials, webhooks-named).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Deploys gmail, telegram, line_notify, google_sheets, http_request, cron
as independent Cloudflare Workers at {name-kebab}.arcrun.dev. Each
wraps the TinyGo WASM from registry/components/{name}/main.go via
wasi-shim cross-import (Method A).
component-loader no longer carries BUILTIN_API_RECIPES — those
hardcoded gmail.googleapis.com / api.telegram.org / sheets / line-notify
endpoints all lived in TS, violating "all business logic in WASM".
Resolution chain now routes the 6 canonical IDs straight to their
{name}.arcrun.dev Worker URLs via WASM_HTTP_RUNNER_IDS.
Per .agents/specs/arcrun/credential-primitives-wasm Phase 3.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- registry/components/auth_service_account: TinyGo impl for Google
Service Account (JWT-bearer → token exchange) and base structure
for AWS SigV4.
- .component-builds/auth_service_account: independent Worker at
auth-service-account.arcrun.dev, extends wasi-shim with an
http_request host function for the token exchange step.
- Delete cypher-executor/src/lib/wasm-executor.ts (legacy, replaced
by component-loader WASM HTTP runner path).
- credential-injector.ts service_account branch now throws — all
service_account recipes must route through auth-dispatcher.
Per .agents/specs/arcrun/credential-primitives-wasm Phase 2.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
credentials/ was a leftover duplicate — all credential routes already live
in cypher-executor/src/routes/credentials.ts. Adds the SDD protocol,
tech-stack, forbidden-list, component-architecture, and progress rules
that guide Phase 1-6 refactors.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- /cypher/execute now accepts separate `config` field:
{node_name: {component: "cmp_19e62efd", ...staticParams}}
- graph-builder reads config[node].component to override componentId
(supports cmp_ hash, rec_ hash, or canonical_id)
- config[node] other fields become node.data (static params merged at runtime)
- acr run now sends workflow.config as separate `config` (not flattened into context)
- context is now only --input dynamic params
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add 15 [[services]] bindings in cypher-executor wrangler.toml
- component-loader now calls logic Workers via Service Binding (svc.fetch)
instead of public URL fetch (which caused 522 timeout within same zone)
- Fallback to public URL if binding not available (dev/testing)
- Add ServiceBinding type to Bindings
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Logic components (15): each deployed as Worker at {name}.arcrun.dev,
cypher-executor fetches them via HTTP POST
- API components (6): gmail, telegram, line_notify, google_sheets,
http_request, cron executed inline via fetch recipes in component-loader
- External URL support: any https:// componentId is fetched directly
(n8n webhooks, MCP endpoints, etc.)
- Add deploy-logic-components.sh script for building/deploying WASM Workers
- Add component-worker-template with inline WASI shim
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rewrote createComponentLoader to directly use createWasiShim inline
instead of calling executeWasm(componentId, buffer, ctx) which doesn't
match wasm-executor's actual signature of executeWasm(input, options).
Also adds Module caching to avoid recompiling WASM on every request.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously, the last node in any triplet chain was classified as Output type
and skipped by the executor (passthrough only). Now only nodes explicitly named
output/result/end/done are Output; all other sink nodes are Component and
will have their WASM executed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add all valid EdgeTypes to graphSchema.edges.type enum
- Add label field to graphSchema.nodes (graph-builder passes it)
- Was causing 圖定義產生失敗 for all /cypher/execute calls
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- POST /register on cypher.arcrun.dev: HMAC-SHA256(email, ENCRYPTION_KEY) → ak_{32hex}, no DB needed
- acr run: Mode 1 (standard/local) now finds local YAML and POSTs to /cypher/execute inline
- acr init: fix register URL → cypher.arcrun.dev/register; fix local mode description
- acr init --local: creates hello.yaml example workflow
- cli v1.0.3 published
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Auto-deploys on push to main when files in cypher-executor/, registry/,
or credentials/ change. Manual dispatch deploys all three.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
A. acr init --local: new local mode, no Cloudflare account required;
config defaults to mode:local when ~/.arcrun/config.yaml missing
B. validate node-count bug: removed faulty input/output node heuristic
that dropped start/end nodes from config check; now all nodes except
reserved 'input' keyword must have config entries
C. acr validate --offline: skip remote component-existence and credentials
checks; local mode also auto-skips these checks
D. parts.ts: replace require('node:fs') with static import (ES module fix)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Problem: canonical_id is readable but mutable; if a component is renamed,
all workflows referencing it by canonical_id break.
Solution: dual-id system
- component_hash_id: cmp_{sha256(canonical_id).slice(0,8)}, derived deterministically,
never changes, safe for workflow references
- canonical_id: human-readable name, used for search and display
- idx:{canonical_id} KV key: reverse-lookup index for resolving canonical_id → hash_id
Changes:
- types.ts: SandboxResult.component_id → component_hash_id + canonical_id,
added 'data' to category enum
- submitComponent.ts: deriveHashId(), writes idx: reverse-lookup on submit
- queryComponents.ts: full rewrite — removed KBDB dependency, uses SUBMISSIONS_KV;
supports both cmp_* and canonical_id as query id; Phase 0 keyword search
with note to upgrade to Vectorize in Phase 2
- sandboxAcceptance.ts: updated field names, fixed TextDecoder TS type
- ensureTemplate.ts: removed KBDB dependency, now a KV health check
- tests: updated component_id → canonical_id
- CONTRIBUTING.md: explain hash_id derivation and dual-id workflow reference syntax
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- registry/aliases.yaml: scope-level synonym table for 21 built-in components
covers api (gmail/google_sheets/telegram/line_notify/http_request),
data (string/array/date/number/json), logic (if/foreach/switch/try_catch/wait),
ai scopes; includes zh/en/abbrev variants
- types.ts: add optional aliases[] field to ComponentContractSchema
- CONTRIBUTING.md: explain aliases auto-merge from aliases.yaml vs manual contract aliases
Note: manual maintenance for now; aliases.yaml becomes KBDB synonym graph seed data
when KBDB is introduced.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>