diff --git a/HEARTBEAT.md b/HEARTBEAT.md deleted file mode 100644 index 627a769d..00000000 --- a/HEARTBEAT.md +++ /dev/null @@ -1,107 +0,0 @@ -# Mission Control Orchestrator Instructions - -You are the Mission Control orchestrator. Your job is to: -1. Claim unassigned tasks (FIFO) -2. Execute work (optionally spawn sub-agents) -3. Log progress and deliverables -4. Move tasks to review when complete - -## CRITICAL: You MUST call Mission Control APIs - -Every action you take MUST be reflected in Mission Control via API calls. The dashboard shows task status in real-time. - -## Required Inputs - -- `BASE_URL` (e.g., http://localhost:8000) -- `ORG_ID` -- `WORKSPACE_ID` -- `AGENT_TOKEN` (Authorization Bearer token) - -## On Every Heartbeat - -### Step 1: Claim next task (FIFO) -```bash -curl -s -X POST "$BASE_URL/api/v1/orgs/$ORG_ID/workspaces/$WORKSPACE_ID/tasks/claim-next" \ - -H "Authorization: Bearer $AGENT_TOKEN" -``` - -- If response is **204**, there is no work. Wait and retry. -- If response returns a task, process it. - -### Step 2: Check your in-progress tasks -```bash -curl -s "$BASE_URL/api/v1/orgs/$ORG_ID/workspaces/$WORKSPACE_ID/tasks?status_filter=in_progress&assigned_agent_id=$AGENT_ID" \ - -H "Authorization: Bearer $AGENT_TOKEN" -``` - -If tasks exist, continue work and update activity/deliverables. - -## When Processing a New Task - -### 1) Log that you're starting -```bash -curl -X POST "$BASE_URL/api/v1/orgs/$ORG_ID/workspaces/$WORKSPACE_ID/tasks/{TASK_ID}/activities" \ - -H "Authorization: Bearer $AGENT_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"activity_type": "updated", "message": "Starting work on task"}' -``` - -### 2) Register a sub-agent (if you spawn one) -```bash -curl -X POST "$BASE_URL/api/v1/orgs/$ORG_ID/workspaces/$WORKSPACE_ID/tasks/{TASK_ID}/subagents" \ - -H "Authorization: Bearer $AGENT_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "openclaw_session_id": "optional-session-id", - "agent_name": "Designer" - }' -``` - -### 3) Register deliverables -```bash -curl -X POST "$BASE_URL/api/v1/orgs/$ORG_ID/workspaces/$WORKSPACE_ID/tasks/{TASK_ID}/deliverables" \ - -H "Authorization: Bearer $AGENT_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "title": "Homepage Design", - "markdown_content": "## Summary\n- Implemented layout\n- Added responsive styles" - }' -``` - -### 4) Log completion -```bash -curl -X POST "$BASE_URL/api/v1/orgs/$ORG_ID/workspaces/$WORKSPACE_ID/tasks/{TASK_ID}/activities" \ - -H "Authorization: Bearer $AGENT_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"activity_type": "completed", "message": "Task completed successfully"}' -``` - -### 5) Move task to REVIEW -```bash -curl -X POST "$BASE_URL/api/v1/orgs/$ORG_ID/workspaces/$WORKSPACE_ID/tasks/{TASK_ID}/transition" \ - -H "Authorization: Bearer $AGENT_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"to_status": "review"}' -``` - -## Task Statuses - -``` -inbox → in_progress → review → done -``` - -Other statuses may be used if configured (`assigned`, `testing`), but the default flow above is expected. - -## Checklist Before Saying HEARTBEAT_OK - -Before responding with HEARTBEAT_OK, verify: -- [ ] No unclaimed tasks remain in INBOX -- [ ] All in-progress tasks have recent activity updates -- [ ] Completed work has deliverables registered -- [ ] Completed tasks are moved to REVIEW - -If ANY of these are false, take action instead of saying HEARTBEAT_OK. - -## Reference - -Full API documentation: See ORCHESTRATION.md in this project. diff --git a/ORCHESTRATION.md b/ORCHESTRATION.md deleted file mode 100644 index 3e7a75ed..00000000 --- a/ORCHESTRATION.md +++ /dev/null @@ -1,176 +0,0 @@ -# Mission Control Orchestration Guide - -This document explains how to orchestrate tasks in Mission Control, including how to: -- Register sub-agents -- Log activities -- Track deliverables -- Update task status - -## API Base URL - -``` -http://localhost:8000 -``` - -Or use the `BASE_URL` environment variable. - -## Task Lifecycle - -``` -INBOX → IN_PROGRESS → REVIEW → DONE -``` - -**Status Descriptions:** -- **INBOX**: New tasks awaiting processing -- **IN_PROGRESS**: Agent actively working on the task -- **REVIEW**: Agent finished, awaiting human approval -- **DONE**: Task completed and approved - -Optional statuses may be enabled (`ASSIGNED`, `TESTING`) but are not required by default. - -## When You Receive a Task - -When a task is claimed, the response includes: -- Task ID -- Title, description, priority -- Project ID - -## Required API Calls - -### 1. Register Sub-Agent (when spawning a worker) - -```bash -curl -X POST "$BASE_URL/api/v1/orgs/$ORG_ID/workspaces/$WORKSPACE_ID/tasks/{TASK_ID}/subagents" \ - -H "Authorization: Bearer $AGENT_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "openclaw_session_id": "unique-session-id", - "agent_name": "Designer" - }' -``` - -### 2. Log Activity (for each significant action) - -```bash -curl -X POST "$BASE_URL/api/v1/orgs/$ORG_ID/workspaces/$WORKSPACE_ID/tasks/{TASK_ID}/activities" \ - -H "Authorization: Bearer $AGENT_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "activity_type": "updated", - "message": "Started working on design mockups" - }' -``` - -Activity types: -- `spawned` - When sub-agent starts -- `updated` - Progress update -- `completed` - Work finished -- `file_created` - Created a deliverable -- `status_changed` - Task moved to new status - -### 3. Register Deliverable (for each output) - -```bash -curl -X POST "$BASE_URL/api/v1/orgs/$ORG_ID/workspaces/$WORKSPACE_ID/tasks/{TASK_ID}/deliverables" \ - -H "Authorization: Bearer $AGENT_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "title": "Homepage Design", - "markdown_content": "## Summary\n- Implemented layout\n- Added responsive styles" - }' -``` - -### 4. Update Task Status - -```bash -curl -X POST "$BASE_URL/api/v1/orgs/$ORG_ID/workspaces/$WORKSPACE_ID/tasks/{TASK_ID}/transition" \ - -H "Authorization: Bearer $AGENT_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ "to_status": "review" }' -``` - -## Complete Example Workflow - -```bash -TASK_ID="abc-123" -BASE_URL="http://localhost:8000" -ORG_ID="org-uuid" -WORKSPACE_ID="workspace-uuid" -AGENT_TOKEN="agent-token" - -# 1) Log that you're starting -curl -X POST "$BASE_URL/api/v1/orgs/$ORG_ID/workspaces/$WORKSPACE_ID/tasks/$TASK_ID/activities" \ - -H "Authorization: Bearer $AGENT_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"activity_type": "updated", "message": "Starting work on task"}' - -# 2) Spawn a sub-agent -curl -X POST "$BASE_URL/api/v1/orgs/$ORG_ID/workspaces/$WORKSPACE_ID/tasks/$TASK_ID/subagents" \ - -H "Authorization: Bearer $AGENT_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"openclaw_session_id": "subagent-'$(date +%s)'", "agent_name": "Designer"}' - -# 3) Register the deliverable -curl -X POST "$BASE_URL/api/v1/orgs/$ORG_ID/workspaces/$WORKSPACE_ID/tasks/$TASK_ID/deliverables" \ - -H "Authorization: Bearer $AGENT_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "title": "Completed Design", - "markdown_content": "## Deliverable\n- Final design with all requested features" - }' - -# 4) Log completion -curl -X POST "$BASE_URL/api/v1/orgs/$ORG_ID/workspaces/$WORKSPACE_ID/tasks/$TASK_ID/activities" \ - -H "Authorization: Bearer $AGENT_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"activity_type": "completed", "message": "Design completed successfully"}' - -# 5) Move to review -curl -X POST "$BASE_URL/api/v1/orgs/$ORG_ID/workspaces/$WORKSPACE_ID/tasks/$TASK_ID/transition" \ - -H "Authorization: Bearer $AGENT_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"to_status": "review"}' -``` - -## Endpoints Reference - -| Endpoint | Method | Purpose | -|----------|--------|---------| -| `/api/v1/orgs/{org_id}/workspaces/{workspace_id}/tasks` | GET | List tasks | -| `/api/v1/orgs/{org_id}/workspaces/{workspace_id}/tasks` | POST | Create task | -| `/api/v1/orgs/{org_id}/workspaces/{workspace_id}/tasks/{task_id}` | PATCH | Update task | -| `/api/v1/orgs/{org_id}/workspaces/{workspace_id}/tasks/{task_id}/activities` | GET | List activities | -| `/api/v1/orgs/{org_id}/workspaces/{workspace_id}/tasks/{task_id}/activities` | POST | Log activity | -| `/api/v1/orgs/{org_id}/workspaces/{workspace_id}/tasks/{task_id}/deliverables` | GET | List deliverables | -| `/api/v1/orgs/{org_id}/workspaces/{workspace_id}/tasks/{task_id}/deliverables` | POST | Add deliverable | -| `/api/v1/orgs/{org_id}/workspaces/{workspace_id}/tasks/{task_id}/subagents` | GET | List sub-agents | -| `/api/v1/orgs/{org_id}/workspaces/{workspace_id}/tasks/{task_id}/subagents` | POST | Register sub-agent | -| `/api/v1/orgs/{org_id}/workspaces/{workspace_id}/tasks/claim-next` | POST | Claim next task (FIFO) | -| `/api/v1/orgs/{org_id}/workspaces/{workspace_id}/events/activities` | GET | SSE activity stream | - -## Activity Body Schema - -```json -{ - "activity_type": "spawned|updated|completed|file_created|status_changed", - "message": "Human-readable description of what happened" -} -``` - -## Deliverable Body Schema - -```json -{ - "title": "Display name for the deliverable", - "markdown_content": "Markdown content for the deliverable" -} -``` - -## Sub-Agent Body Schema - -```json -{ - "openclaw_session_id": "unique-identifier-for-session", - "agent_name": "Designer|Developer|Researcher|Writer" -} -``` diff --git a/backend/.env.example b/backend/.env.example index c5b23175..b79207c5 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -3,6 +3,7 @@ LOG_LEVEL=INFO DATABASE_URL=postgresql+psycopg://postgres:postgres@localhost:5432/openclaw_agency REDIS_URL=redis://localhost:6379/0 CORS_ORIGINS=http://localhost:3000 +BASE_URL= # Clerk (auth only) CLERK_JWKS_URL= @@ -12,6 +13,8 @@ CLERK_LEEWAY=10.0 # OpenClaw Gateway OPENCLAW_GATEWAY_URL=ws://127.0.0.1:18789 OPENCLAW_GATEWAY_TOKEN= +OPENCLAW_MAIN_SESSION_KEY=agent:main:main +OPENCLAW_WORKSPACE_ROOT=~/.openclaw/workspaces # Database DB_AUTO_MIGRATE=false diff --git a/backend/app/api/agents.py b/backend/app/api/agents.py index 0b96f4cb..a799d8e6 100644 --- a/backend/app/api/agents.py +++ b/backend/app/api/agents.py @@ -20,11 +20,12 @@ from app.schemas.agents import ( AgentUpdate, ) from app.services.admin_access import require_admin +from app.services.agent_provisioning import send_provisioning_message router = APIRouter(prefix="/agents", tags=["agents"]) OFFLINE_AFTER = timedelta(minutes=10) -DEFAULT_GATEWAY_CHANNEL = "openclaw-agency" +AGENT_SESSION_PREFIX = "agent" def _slugify(value: str) -> str: @@ -32,17 +33,17 @@ def _slugify(value: str) -> str: return slug or uuid4().hex -def _build_session_label(agent_name: str) -> str: - return f"{DEFAULT_GATEWAY_CHANNEL}-{_slugify(agent_name)}" +def _build_session_key(agent_name: str) -> str: + return f"{AGENT_SESSION_PREFIX}:{_slugify(agent_name)}:main" -async def _create_gateway_session(agent_name: str) -> str: - label = _build_session_label(agent_name) +async def _ensure_gateway_session(agent_name: str) -> tuple[str, str | None]: + session_key = _build_session_key(agent_name) try: - await openclaw_call("sessions.patch", {"key": label, "label": agent_name}) + await openclaw_call("sessions.patch", {"key": session_key, "label": agent_name}) + return session_key, None except OpenClawGatewayError as exc: - raise HTTPException(status_code=status.HTTP_502_BAD_GATEWAY, detail=str(exc)) from exc - return label + return session_key, str(exc) def _with_computed_status(agent: Agent) -> Agent: @@ -79,18 +80,48 @@ async def create_agent( ) -> Agent: require_admin(auth) agent = Agent.model_validate(payload) - agent.openclaw_session_id = await _create_gateway_session(agent.name) + session_key, session_error = await _ensure_gateway_session(agent.name) + agent.openclaw_session_id = session_key session.add(agent) session.commit() session.refresh(agent) - session.add( - ActivityEvent( - event_type="agent.session.created", - message=f"Session created for {agent.name}.", - agent_id=agent.id, + if session_error: + session.add( + ActivityEvent( + event_type="agent.session.failed", + message=f"Session sync failed for {agent.name}: {session_error}", + agent_id=agent.id, + ) + ) + else: + session.add( + ActivityEvent( + event_type="agent.session.created", + message=f"Session created for {agent.name}.", + agent_id=agent.id, + ) ) - ) session.commit() + try: + await send_provisioning_message(agent) + except OpenClawGatewayError as exc: + session.add( + ActivityEvent( + event_type="agent.provision.failed", + message=f"Provisioning message failed: {exc}", + agent_id=agent.id, + ) + ) + session.commit() + except Exception as exc: # pragma: no cover - unexpected provisioning errors + session.add( + ActivityEvent( + event_type="agent.provision.failed", + message=f"Provisioning message failed: {exc}", + agent_id=agent.id, + ) + ) + session.commit() return agent @@ -160,26 +191,88 @@ async def heartbeat_or_create_agent( agent = session.exec(select(Agent).where(Agent.name == payload.name)).first() if agent is None: agent = Agent(name=payload.name, status=payload.status or "online") - agent.openclaw_session_id = await _create_gateway_session(agent.name) + session_key, session_error = await _ensure_gateway_session(agent.name) + agent.openclaw_session_id = session_key session.add(agent) session.commit() session.refresh(agent) - session.add( - ActivityEvent( - event_type="agent.session.created", - message=f"Session created for {agent.name}.", - agent_id=agent.id, + if session_error: + session.add( + ActivityEvent( + event_type="agent.session.failed", + message=f"Session sync failed for {agent.name}: {session_error}", + agent_id=agent.id, + ) ) - ) + else: + session.add( + ActivityEvent( + event_type="agent.session.created", + message=f"Session created for {agent.name}.", + agent_id=agent.id, + ) + ) + session.commit() + try: + await send_provisioning_message(agent) + except OpenClawGatewayError as exc: + session.add( + ActivityEvent( + event_type="agent.provision.failed", + message=f"Provisioning message failed: {exc}", + agent_id=agent.id, + ) + ) + session.commit() + except Exception as exc: # pragma: no cover - unexpected provisioning errors + session.add( + ActivityEvent( + event_type="agent.provision.failed", + message=f"Provisioning message failed: {exc}", + agent_id=agent.id, + ) + ) + session.commit() elif not agent.openclaw_session_id: - agent.openclaw_session_id = await _create_gateway_session(agent.name) - session.add( - ActivityEvent( - event_type="agent.session.created", - message=f"Session created for {agent.name}.", - agent_id=agent.id, + session_key, session_error = await _ensure_gateway_session(agent.name) + agent.openclaw_session_id = session_key + if session_error: + session.add( + ActivityEvent( + event_type="agent.session.failed", + message=f"Session sync failed for {agent.name}: {session_error}", + agent_id=agent.id, + ) ) - ) + else: + session.add( + ActivityEvent( + event_type="agent.session.created", + message=f"Session created for {agent.name}.", + agent_id=agent.id, + ) + ) + session.commit() + try: + await send_provisioning_message(agent) + except OpenClawGatewayError as exc: + session.add( + ActivityEvent( + event_type="agent.provision.failed", + message=f"Provisioning message failed: {exc}", + agent_id=agent.id, + ) + ) + session.commit() + except Exception as exc: # pragma: no cover - unexpected provisioning errors + session.add( + ActivityEvent( + event_type="agent.provision.failed", + message=f"Provisioning message failed: {exc}", + agent_id=agent.id, + ) + ) + session.commit() if payload.status: agent.status = payload.status agent.last_seen_at = datetime.utcnow() diff --git a/backend/app/core/config.py b/backend/app/core/config.py index 9f1ded46..af22ac40 100644 --- a/backend/app/core/config.py +++ b/backend/app/core/config.py @@ -22,8 +22,11 @@ class Settings(BaseSettings): # OpenClaw Gateway openclaw_gateway_url: str = "" openclaw_gateway_token: str = "" + openclaw_main_session_key: str = "agent:main:main" + openclaw_workspace_root: str = "~/.openclaw/workspaces" cors_origins: str = "" + base_url: str = "" # Database lifecycle db_auto_migrate: bool = False diff --git a/backend/app/services/agent_provisioning.py b/backend/app/services/agent_provisioning.py new file mode 100644 index 00000000..c40c2354 --- /dev/null +++ b/backend/app/services/agent_provisioning.py @@ -0,0 +1,93 @@ +from __future__ import annotations + +import re +from pathlib import Path +from uuid import uuid4 + +from app.core.config import settings +from app.integrations.openclaw_gateway import send_message +from app.models.agents import Agent + +TEMPLATE_FILES = [ + "AGENTS.md", + "BOOT.md", + "BOOTSTRAP.md", + "HEARTBEAT.md", + "IDENTITY.md", + "SOUL.md", + "TOOLS.md", + "USER.md", +] + + +def _repo_root() -> Path: + return Path(__file__).resolve().parents[3] + + +def _templates_root() -> Path: + return _repo_root() / "templates" + + +def _slugify(value: str) -> str: + slug = re.sub(r"[^a-z0-9]+", "-", value.lower()).strip("-") + return slug or uuid4().hex + + +def _read_templates() -> dict[str, str]: + root = _templates_root() + templates: dict[str, str] = {} + for name in TEMPLATE_FILES: + path = root / name + if path.exists(): + templates[name] = path.read_text(encoding="utf-8").strip() + else: + templates[name] = "" + return templates + + +def _render_file_block(name: str, content: str) -> str: + body = content if content else f"# {name}\n\nTODO: add content\n" + return f"\n{name}\n```md\n{body}\n```\n" + + +def _workspace_path(agent_name: str) -> str: + root = settings.openclaw_workspace_root or "~/.openclaw/workspaces" + root = root.rstrip("/") + return f"{root}/{_slugify(agent_name)}" + + +def build_provisioning_message(agent: Agent) -> str: + templates = _read_templates() + agent_id = _slugify(agent.name) + workspace_path = _workspace_path(agent.name) + session_key = agent.openclaw_session_id or "" + base_url = settings.base_url or "" + + file_blocks = "".join( + _render_file_block(name, templates.get(name, "")) for name in TEMPLATE_FILES + ) + + return ( + "Provision a new OpenClaw agent workspace.\n\n" + f"Agent name: {agent.name}\n" + f"Agent id: {agent_id}\n" + f"Session key: {session_key}\n" + f"Workspace path: {workspace_path}\n\n" + f"Base URL: {base_url or 'UNSET'}\n\n" + "Steps:\n" + "1) Create the workspace directory.\n" + "2) Write the files below with the exact contents.\n" + f"3) Set BASE_URL to {base_url or '{{BASE_URL}}'} for the agent runtime.\n" + "4) Replace placeholders like {{AGENT_NAME}}, {{AGENT_ID}}, {{BASE_URL}}, {{AUTH_TOKEN}}.\n" + "5) Leave BOOTSTRAP.md in place; the agent should run it on first start and delete it.\n" + "6) Register agent id in OpenClaw so it uses this workspace path.\n\n" + "Files:" + file_blocks + ) + + +async def send_provisioning_message(agent: Agent) -> None: + main_session = settings.openclaw_main_session_key + if not main_session: + return + message = build_provisioning_message(agent) + await send_message(message, session_key=main_session, deliver=False) diff --git a/templates/AGENTS.md b/templates/AGENTS.md new file mode 100644 index 00000000..94c5dbfe --- /dev/null +++ b/templates/AGENTS.md @@ -0,0 +1,30 @@ +# AGENTS.md + +This workspace is your home. Treat it as the source of truth. + +## First run +- If BOOTSTRAP.md exists, follow it once and delete it when finished. + +## Every session +Before doing anything else: +1) Read SOUL.md (identity, boundaries) +2) Read USER.md (who you serve) +3) Read memory/YYYY-MM-DD.md for today and yesterday (create memory/ if missing) +4) If this is the main or direct session, also read memory.md + +## Memory +- Daily log: memory/YYYY-MM-DD.md +- Long-term: memory.md (main session only) +Write things down. Do not rely on short-term context. + +## Safety +- Ask before destructive actions. +- Prefer reversible steps. +- Do not exfiltrate private data. + +## Tools +- Skills are authoritative. Follow SKILL.md instructions exactly. +- Use TOOLS.md for environment-specific notes. + +## Heartbeats +- HEARTBEAT.md defines what to do on each heartbeat. diff --git a/templates/BOOT.md b/templates/BOOT.md new file mode 100644 index 00000000..4ce5c83a --- /dev/null +++ b/templates/BOOT.md @@ -0,0 +1,6 @@ +# BOOT.md + +On startup: +1) Verify API reachability (GET {{BASE_URL}}/api/v1/gateway/status). +2) If you send a boot message, end with NO_REPLY. +3) If BOOTSTRAP.md exists in this workspace, the agent should run it once and delete it. diff --git a/templates/BOOTSTRAP.md b/templates/BOOTSTRAP.md new file mode 100644 index 00000000..4960d8dc --- /dev/null +++ b/templates/BOOTSTRAP.md @@ -0,0 +1,8 @@ +# BOOTSTRAP.md + +First run checklist: +1) Fill IDENTITY.md (name, vibe, emoji, avatar). +2) Fill USER.md with the human context. +3) Create memory/ and memory.md if missing. +4) Read SOUL.md and update if needed. +5) Delete this file when done. diff --git a/templates/HEARTBEAT.md b/templates/HEARTBEAT.md new file mode 100644 index 00000000..ef3b71d2 --- /dev/null +++ b/templates/HEARTBEAT.md @@ -0,0 +1,56 @@ +# HEARTBEAT.md + +If this file is empty, skip heartbeat work. + +## Required inputs +- BASE_URL (e.g. http://localhost:8000) +- AUTH_TOKEN (Bearer token) +- AGENT_NAME + +## On every heartbeat +1) Check in: +```bash +curl -s -X POST "$BASE_URL/api/v1/agents/heartbeat" \ + -H "Authorization: Bearer $AUTH_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"name": "'$AGENT_NAME'", "status": "online"}' +``` + +2) List boards: +```bash +curl -s "$BASE_URL/api/v1/boards" \ + -H "Authorization: Bearer $AUTH_TOKEN" +``` + +3) For each board, list tasks: +```bash +curl -s "$BASE_URL/api/v1/boards/{BOARD_ID}/tasks" \ + -H "Authorization: Bearer $AUTH_TOKEN" +``` + +4) Claim next task (FIFO): +- Find the oldest task with status "inbox" across all boards. +- Claim it by moving it to "in_progress": +```bash +curl -s -X PATCH "$BASE_URL/api/v1/boards/{BOARD_ID}/tasks/{TASK_ID}" \ + -H "Authorization: Bearer $AUTH_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"status": "in_progress"}' +``` + +5) Work the task: +- Update status as you progress. +- When complete, move to "review": +```bash +curl -s -X PATCH "$BASE_URL/api/v1/boards/{BOARD_ID}/tasks/{TASK_ID}" \ + -H "Authorization: Bearer $AUTH_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"status": "review"}' +``` + +## Status flow +``` +inbox -> in_progress -> review -> done +``` + +Do not say HEARTBEAT_OK if there is inbox work or active in_progress work. diff --git a/templates/IDENTITY.md b/templates/IDENTITY.md new file mode 100644 index 00000000..6c362c75 --- /dev/null +++ b/templates/IDENTITY.md @@ -0,0 +1,8 @@ +# IDENTITY.md + +Name: {{AGENT_NAME}} +Agent ID: {{AGENT_ID}} +Creature: AI +Vibe: calm, precise, helpful +Emoji: :gear: +Avatar: avatars/{{AGENT_ID}}.png diff --git a/templates/SOUL.md b/templates/SOUL.md new file mode 100644 index 00000000..7ea65ff0 --- /dev/null +++ b/templates/SOUL.md @@ -0,0 +1,16 @@ +# SOUL.md + +You are a Mission Control agent for the openclaw-agency app. + +Core truths: +- Keep tasks moving and statuses accurate. +- Write concise, factual updates. +- Prefer small, reversible steps. + +Boundaries: +- Ask before destructive actions. +- Do not invent APIs or data. +- Avoid leaking sensitive information. + +Continuity: +- Record decisions and conventions in memory files. diff --git a/templates/TOOLS.md b/templates/TOOLS.md new file mode 100644 index 00000000..2be0473e --- /dev/null +++ b/templates/TOOLS.md @@ -0,0 +1,10 @@ +# TOOLS.md + +BASE_URL={{BASE_URL}} +AUTH_TOKEN={{AUTH_TOKEN}} +MAIN_SESSION_KEY=agent:main:main +WORKSPACE_ROOT=~/.openclaw/workspaces + +Notes: +- Use curl for API calls. +- Keep outputs short and log progress via task status changes. diff --git a/templates/USER.md b/templates/USER.md new file mode 100644 index 00000000..8e08ed81 --- /dev/null +++ b/templates/USER.md @@ -0,0 +1,7 @@ +# USER.md + +Name: {{USER_NAME}} +Preferred name: {{USER_PREFERRED_NAME}} +Timezone: {{USER_TIMEZONE}} +Notes: +- {{USER_NOTES}}