Ocawe is a Crystal-first runtime for workflow bundles, agents, tools, and skills.
Licenses: ISC (LICENSE) and 0BSD (LICENSE-0BSD).
It includes:
- A production-oriented HTTP runtime server.
- A Svelte playground for workflows, tools, skills, and agent chat.
- VitePress docs with a custom
/playground/route.
- Crystal workflow runtime with ACD-style bundles (
*.acd.cr). - Agent + skill + tool discovery from workflow directories.
- Voice and RAG patterns through workflow DSL.
- Schema validation and guardrails in agent/workflow execution.
- OpenAI-compatible chat completions endpoint support.
Build CLI:
crystal build src/cli/main.cr -o build/ocaweocawe build/dev/up now auto-bootstrap Crystal when crystal is missing by downloading a platform archive into ./.tools/crystal.
You can control bootstrap with env vars:
OCAWE_CRYSTAL_VERSION(default1.13.3)OCAWE_CRYSTAL_BASE_URL(default Crystal GitHub releases URL)OCAWE_CRYSTAL_FORCE_BOOTSTRAP=1(force local toolchain even if systemcrystalexists)OCAWE_CRYSTAL_VERBOSE=1(print toolchain version during bootstrap)
Run runtime server:
./build/ocawe up --port 4111codex and other provider CLIs are installed inside the container on demand (no /root/.nvm bind and no custom PATH env needed).
For auth, mount only /root/.codex.
services:
ocawe:
image: ocawe:test
container_name: ocawe-solver
ports:
- "4111:4111"
environment:
- OCAWE_BUILD_ARGS=--release
- OCAWE_CONFIG_RCL=/ocawe/ocawe.config.rcl
volumes:
- ./ocawe.config.rcl:/ocawe/ocawe.config.rcl:ro
- /root/.codex:/root/.codex
restart: unless-stoppedFull compose example file: docker-compose.solver-full-example.yml.
Provider credential forwarding workflows:
provider-credentials-codexprovider-credentials-claudeprovider-credentials-opencodeprovider-credentials-qwen
Start and test:
docker compose -f docker-compose.solver-full-example.yml up -d --build
curl -sS http://127.0.0.1:4111/v1/workflows | jq
curl -sS -X POST http://127.0.0.1:4111/v1/workflows/provider-credentials-codex/runs \
-H 'content-type: application/json' \
-d '{"input":{"content":"run mock credentials check"}}' | jqThe flow runs tools/mock-data.rb (Ruby), saves a file under /ocawe/.ocawe/mock-data, then runs agent_codex through tools/mock-agent-cli.rb, which saves a credentials report under /ocawe/.ocawe/mock-agent.
Direct local demo (without HTTP runtime):
PATH="/tmp/fakebin:$PATH" crystal run scripts/provider_credentials_demo.crThis executes agent_codex, agent_claude_code, agent_opencode, and agent_qwen handlers directly, verifies forwarded credential/config paths, and writes:
- mock data file under
./.tmp/mock-data - provider reports under
./.tmp/mock-agent
Run playground:
cd packages/playground
bun install
bun run devRun docs:
cd packages/docs
bun install
bun run dev./build/ocawe build --release
./build/ocawe dev --port 4111
./build/ocawe up --port 4111
# explicit workflow trigger by id
./build/ocawe workflow solver task=deploy env=prod
# agent/function/tool/skill/support triggers
./build/ocawe agent code-reviewer --prompt "review this patch"
./build/ocawe tool project_healthcheck
./build/ocawe support onboarding-check
# alias executable style (workflow id from executable name)
ln -sf ./build/ocawe /usr/local/bin/ocawe_example_workflow
ocawe_example_workflowWorkflow trigger CLI calls POST /v1/triggers/workflows/:id and sends:
input.<key>fromkey=valueargs (values parsed as JSON when possible).input.argsfrom positional args without=.
Trigger command mapping:
workflow->/v1/triggers/workflows/:idagent->/v1/triggers/agents/:idskill/support->/v1/triggers/skills/:idfunction/tool->/v1/triggers/functions/:id
Use OCAWE_TRIGGER_BASE_URL or --base-url to target a non-default runtime URL.
Primary APIs:
GET /v1/workflowsPOST /v1/workflows/:workflowId/runsGET /v1/toolsGET /v1/skillsGET /v1/agentsPOST /v1/agents/:agentId/generateGET /v1/mcp/serversPOST /v1/mcp/serversGET /v1/mcp/catalogPOST /mcp
Compatibility:
POST /v1/chat/completions
Federation APIs:
POST /actors/{identifier}/inbox(S2S inbound activities, signature-verified)GET /actors/{identifier}/outboxPOST /actors/{identifier}/outboxGET /federation/metadata(reported capabilities + supported FEPs from FEDERATION.md)GET /FEDERATION.md(repo interoperability manifest)
S2S ticket ingestion mode:
- follow remote actor and poll remote
outboxforCreate(Ticket)activities - require HTTP Signatures for federation requests
src/
cli/ # ocawe CLI (build/dev/up)
framework/ # runtime framework + HTTP endpoints
packages/
playground/ # Svelte playground (Vite + Bun)
docs/ # VitePress docs and static playground route
shards/examples/ # reference workflow bundles
spec/ # Crystal specs
See shards/examples:
agents-exampleskills-exampleworkflow-examplerag-playgroundvoice-playgroundsimple-model-testfull-capabilitiesconfig-example(Crystal config template)
Run all examples:
./build/ocawe up --port 4111 --workflows-root ./shards/examplesFramework configuration is defined in Crystal code via src/framework/config/settings.cr.
Federation defaults:
- Aptok in-process KV and queues are used by default.
auto_subscriberemains supported for startup remote actor tracking.
Alternative config format (RCL) is also supported.
Static config file ./ocawe.config.rcl is auto-loaded when present.
Example config.rcl:
api = "federation"
federation do
auto_subscribe = [".col.pub"]
end
datasets do
adapter = "file"
file_root = "./.ocawe/datasets"
end
workflows do
preferred_workflows_root = "./workflows"
end
Default static file in repo: ocawe.config.rcl.
api supports string or array of strings:
"federation": ForgeFed-only mode (mounts Aptok ActivityPub routes (/actors/*,/inbox, WebFinger/NodeInfo) plus health/docs)"classic": default runtime APIs (/v1/*)"mastra": backward-compatible alias for"classic"["classic", "federation"]: enable both groups
Federation persistence:
- Federation state is managed through Aptok KV/queue primitives. The current runtime uses in-process Aptok storage; configure durable Aptok storage when adding a persistent deployment adapter.
Function handler selection via RCL:
functions.enabled = ["agent_opencode", "agent_codex", "agent_cliproxy", "agent_claude_code", "agent_qwen"]- handlers are optional and available only if external shard
ocawe-agent-functionsis connected by the host app
Agent CLI defaults:
agent_codex,agent_claude_code,agent_opencode,agent_qwencan auto-install their CLI on first use.CODEX_BIN/CLAUDE_BIN/OPENCODE_BIN/QWEN_BINare optional executable overrides.- per-provider credentials/config paths can be set in node params (
path_to_credentials,path_to_config,path_to_config_codex) or via env. - federation merge runs (
api=federation,activity=merge) inject strict prompt instructions foragent_*to return ForgeFedOffer(Ticket)JSON only.
Minimal workflow snippets:
workflow "solver-codex" do
agent_codex, install_policy: "on_demand", args: ["--skip-git-repo-check"], input_schema: Schema::Types.any(), output_schema: Schema::Types.any()
end
workflow "solver-claude" do
agent_claude_code, install_policy: "on_demand", input_schema: Schema::Types.any(), output_schema: Schema::Types.any()
end
workflow "solver-opencode" do
agent_opencode, install_policy: "on_demand", input_schema: Schema::Types.any(), output_schema: Schema::Types.any()
end
workflow "solver-qwen" do
agent_qwen, install_policy: "on_demand", input_schema: Schema::Types.any(), output_schema: Schema::Types.any()
endMinimal workflow snippets:
workflow "solver-codex" do
agent_codex, install_policy: "on_demand", args: ["--skip-git-repo-check"], input_schema: Schema::Types.any(), output_schema: Schema::Types.any()
end
workflow "solver-claude" do
agent_claude_code, install_policy: "on_demand", input_schema: Schema::Types.any(), output_schema: Schema::Types.any()
end
workflow "solver-opencode" do
agent_opencode, install_policy: "on_demand", input_schema: Schema::Types.any(), output_schema: Schema::Types.any()
end
workflow "solver-qwen" do
agent_qwen, install_policy: "on_demand", input_schema: Schema::Types.any(), output_schema: Schema::Types.any()
endOptional external handler install in host shard.yml:
dependencies:
ocawe:
path: ../ocawe
ocawe-agent-functions:
path: ../ocawe/shards/agent-functionsRun with RCL:
./build/ocawe up --port 4111 --config-rcl ./config.rclOr with env:
OCAWE_CONFIG_RCL=./config.rcl ./build/ocawe up --port 4111Template example:
shards/examples/config-example/app_config.cr
The docs site exposes the playground at /playground/.
Build mirrored playground assets:
cd packages/playground
bun run build:docsThen build docs:
cd packages/docs
bun run buildmise run cli-build
mise run up
mise run playground-build
mise run docs-buildcrystal spec
cd packages/playground && bun run lint
cd packages/docs && bun run build