- name
- shift
- description
- Multi-identity delegation for OpenClaw. Turns a single agent into a system of specialized sub-identities (coding, research, quick tasks) each powered by different AI models. Use when: (1) the user asks a coding task (write, debug, implement, refactor, explain code), (2) the user asks for research, analysis, comparison, or explanation, (3) the user asks a quick question, lookup, or reminder, (4) the user asks anything that would benefit from a specialized model. NOT for: trivial greetings, acknowledgments, or meta-conversation about the chat itself. SHIFT handles routing, delegation, sub-identity-to-sub-identity consultation, synthesis, and cost management entirely within one conversation.
# SHIFT โ Multi-Identity Delegation Skill
**One agent. Many specialists. One conversation.**
---
## โ ๏ธ SECURITY AND PRIVACY โ READ BEFORE ENABLING
### What SHIFT Accesses
SHIFT reads from your OpenClaw workspace:
- `~/.openclaw/workspace/MEMORY.md` โ excerpts attached to delegation context
- `~/.openclaw/workspace/.shift/config.yaml` โ your persona and cost settings
- Session files it creates in `~/.openclaw/workspace/.shift/sessions/`
SHIFT writes to:
- `~/.openclaw/workspace/.shift/sessions/<runId>/` โ per-delegation session files
- `~/.openclaw/workspace/.shift/cost-tracking.json` โ delegation cost tracking
- `~/.openclaw/workspace/.shift/personas/*.yaml` โ your persona overrides
### What SHIFT Transmits
When you enable delegation, the following are sent to whatever model providers you configure for each persona:
- Your message content
- Conversation history (last N turns, controlled by `contextBridge.historyTurns`)
- Active file contents and MEMORY.md excerpts relevant to the task
- Delegation metadata (runId, timestamps, persona name)
**You control which models are used.** SHIFT does not ship with or store credentials โ it uses the model providers configured in your OpenClaw agent config. Review your provider's data handling policy.
### Data Exposure Risk
If your workspace files or MEMORY.md contain secrets (API keys, credentials, private data), and those files are referenced in a delegated task, that content will be transmitted to your configured model provider.
**Mitigations:**
- Do not delegate tasks that reference sensitive file paths
- Set `contextBridge.historyTurns` to a low number (e.g., 3)
- Use `costManagement.trackOnly: true` during evaluation to observe behavior without enforcement
- Use trusted or self-hosted model providers for sensitive work
### Setup Script
`scripts/setup.sh` creates local directories only. It does NOT:
- Make network calls
- Escalate privileges
- Modify system files
- Access credentials
### Cost and Consultations
Consultations spawn additional model calls. Costs are tracked in `cost-tracking.json` per delegation. Set `costManagement.trackOnly: true` to monitor before enforcing limits.
### Recommendations
1. Start with `costManagement.trackOnly: true` to observe costs
2. Set `contextBridge.historyTurns` to a small number (5 or less)
3. Set `contextBridge.archiveAfterMinutes: 30` for faster cleanup
4. Do not delegate tasks referencing sensitive file paths
5. Review model providers' data policies before sensitive work
---
Triggers on: any message that might benefit from specialized handling โ coding tasks, research, analysis, quick lookups, or anything that warrants delegating to a sub-identity.
When SHIFT triggers, you read and follows the procedures below to: classify the task, delegate to the right sub-identity, handle consultation between sub-identities, and synthesize the final response in his own voice.
---
# SHIFT Procedures
Follow these steps for every message that triggers SHIFT.
---
## STEP 1 โ Fast Path Check
Before anything, check if this message is trivially handled by you directly.
**Bypass delegation (return `none`) if message is ONLY:**
- Greetings: `hi`, `hey`, `hello`, `yo`, `sup`
- Acknowledgments: `thanks`, `thank you`, `ty`, `ok`, `sure`, `got it`, `makes sense`, `cool`, `nice`
- Meta: `that was fast`, `nice one`, `lol`, `haha`
**If none of those match, proceed to STEP 2.**
---
## STEP 2 โ Load Config
Read the SHIFT config at:
```
~/.openclaw/workspace/.shift/config.yaml
```
If the file doesn't exist, run the setup script first:
```bash
bash ~/.openclaw/workspace/skills/shift/scripts/setup.sh
```
From config, extract:
- `displayMode` โ `hidden` or `transparent`
- `fastPath` โ `conservative` or `off`
- `costManagement.enabled`, `costManagement.costBudgetPerHour`, `costManagement.alertThreshold`
- `contextBridge.historyTurns`, `contextBridge.sessionFolder`
- `personas` โ enabled personas and their settings
---
## STEP 3 โ Cost Budget Check
If `costManagement.enabled: true`:
Read `~/.openclaw/workspace/.shift/cost-tracking.json`:
```json
{
"hourStart": "2026-03-18T15:00:00Z",
"totalSpend": 0.87,
"delegations": [...]
}
```
**If current UTC hour > hourStart (new hour):**
โ Reset `totalSpend: 0`, update `hourStart` to current hour.
**If `totalSpend >= costBudgetPerHour`:**
โ You handle the task directly. Say: *"Handling this one myself to stay within your cost budget."*
Return `budget_exceeded`.
**If `totalSpend >= alertThreshold * costBudgetPerHour`:**
โ Send a quiet warning: *"Approaching delegation budget limit for this hour."*
---
## STEP 4 โ Route to Persona
Using the enabled personas from config, classify the user's message.
### Keyword Scoring
For each enabled persona, count keyword matches in the user's message (case-insensitive, whole-word). Raw score = matches / total keywords.
**If raw score >= `minConfidence`:** Add to candidates.
**Runner special case:** Runner has `requireExplicit: true`. It only triggers if the message is predominantly a Runner task, not just containing a keyword. If the message has strong code/research keywords, Runner is NOT a match even if it has Runner keywords.
### Tie-Breaking
If multiple personas score above threshold:
โ Higher score wins. If tied: codex > researcher > runner.
### Default
If no persona scores above threshold โ You handle directly. Return `none`.
---
## STEP 5 โ Prepare Delegation Context
Generate a unique `runId`:
```
run-{YYYYMMDD}-{HHMM}-{persona}-{sequence}
Example: run-20260318-1551-codex-001
```
Create the session folder:
```
~/.openclaw/workspace/.shift/sessions/{runId}/
```
### Write INBOUND.json
```json
{
"runId": "<runId>",
"timestamp": "<ISO UTC>",
"persona": "<matched persona>",
"userMessage": "<exact user message>",
"masterConversationHistory": <last N turns from conversation>,
"activeFiles": <files mentioned>,
"masterSummary": "<brief summary of conversation so far>"
}
```
### Write CONTEXT.md
Pull from:
- `~/.openclaw/workspace/MEMORY.md` (keyword-matched relevant sections)
- Any active file contents mentioned in the conversation
- Persona-specific context needs (from the persona definition in config)
Format:
```markdown
# Context for {persona}
## Project/Memory (relevant)
...
## Active Files
...
## Persona Context Needs
...
```
---
## STEP 6 โ Build Task Prompt
Construct the prompt for the sub-agent:
```markdown
# You are {persona_name}
## Persona
{persona voice, tone, strengths, blind spots from config}
## Your Task
{user's exact message}
## Context
Before starting, read:
- /path/to/INBOUND.json โ your input and conversation history
- /path/to/CONTEXT.md โ relevant project context
## Your Protocol
1. Read INBOUND.json and CONTEXT.md
2. Execute your task
3. If you need to consult another sub-identity and your persona allows it:
- Write your question to the session folder as CONSULT-INBOUND.md
- Set a timeout: min(remaining_time * 0.5, your consultationTimeout)
- Spawn the target sub-identity using sessions_spawn
- Wait for them to write CONSULT-OUTBOUND.md
- Read their response and continue with that context
4. Write your final result to /path/to/OUTBOUND.md
5. Include a ConsultationLog if you consulted anyone
6. End your response with [DONE]
```
---
## STEP 7 โ Spawn Sub-Agent
```javascript
sessions_spawn({
model: personaConfig.model,
task: taskPrompt,
label: `shift-${persona}-${runId}`,
timeoutSeconds: personaConfig.timeout,
attachments: [
{ name: "INBOUND.json", content: <inboundJsonString> },
{ name: "CONTEXT.md", content: <contextMdString> }
]
})
```
**Track elapsed time.** If `elapsed > timeout * 0.7`:
โ Send status to user: *"{persona} is still working on this..."*
---
## STEP 8 โ Wait and Read Result
Wait for `sessions_spawn` to complete.
### Read OUTBOUND.md
From the session folder:
```
~/.openclaw/workspace/.shift/sessions/{runId}/OUTBOUND.md
```
Parse:
- `Status`: `complete` | `error` | `escalation`
- `Result`: the actual response content
- `ConsultationLog`: if sub-identity consulted another
- `Cost`: token counts if available
### Check for ESCALATE.md (Runner only)
If `Status: escalation`:
โ Runner detected the task was too complex. You take over directly.
โ Read `reason`, `summary`, `partialAnswer` from ESCALATE.md.
โ Incorporate any partial work Runner did.
---
## STEP 9 โ Update Cost Tracking
After successful delegation, update `cost-tracking.json`:
```json
{
"hourStart": "<current hour UTC>",
"totalSpend": <previous + estimated cost>,
"delegations": [
{
"runId": "<runId>",
"persona": "<persona>",
"inputTokens": <from sub-agent result if available>,
"outputTokens": <from sub-agent result if available>,
"estimatedCost": <calculate from model cost config>,
"timestamp": "<now>"
}
]
}
```
---
## STEP 10 โ Synthesize Response
Transform the sub-identity's output into your voice.
### Detection
If `ConsultationLog` is present and non-empty:
โ Build consultation mention (ALWAYS shown):
```
{parent persona} consulted {target persona} on {topic}...
```
### Transformation Rules
| Sub-identity output | your transformation |
|---|---|
| Code | Explain what it does in plain English, highlight key parts, offer to add tests |
| Analysis/Research | Pull 2-3 key insights, bullet-point them, note caveats |
| Quick answer (Runner) | Relay directly with warmth added |
### Display Mode
**Hidden (default):**
```
[Assistant]: Here's the {implementation/analysis/answer}...
```
**Transparent:**
```
[Assistant] โ [{persona}] working on this...
[Assistant] โ [{persona}] done.
[Assistant]: Here's the...
```
Consultation mentions are ALWAYS shown in both modes.
---
## STEP 11 โ Handle Errors
| Scenario | Response |
|---|---|
| Sub-agent timeout | *"Looks like this one is taking longer than expected โ let me work through it directly."* |
| Sub-agent error | *"Hit a snag with the specialist โ let me handle this myself."* |
| sessions_spawn fails | Fall back to your handling directly |
| OUTBOUND.md missing | Assume sub-agent failed, You handle directly |
| Model unavailable | Log warning, You handle directly |
---
# Consultation Protocol (Master-Orchestrated)
**Key insight:** Sub-agent sessions cannot cleanly spawn child sessions and wait. The solution: You orchestrate the consultation from the master level.
## Flow
```
Codex needs context
โ
Codex writes CONSULT-INBOUND.md + OUTBOUND.md (Status: needs_consultation)
โ
You detect needs_consultation flag in OUTBOUND.md
โ
You tell user (transparent mode): "Codex โ [Codex โ Researcher]..."
โ
You spawn Researcher with CONSULT-INBOUND.md
โ
Researcher writes CONSULT-OUTBOUND.md
โ
You read it, appends to Codex's CONTEXT.md
โ
You re-spawn Codex with enriched context (brief task: "continue with this context")
โ
Codex writes final OUTBOUND.md with ConsultationLog
โ
You synthesize โ mentions the consultation (always visible)
```
## Sub-Agent Side (Codex/Researcher)
When a sub-agent needs to consult another sub-identity:
1. Check: is target in my `consults` list? Is target NOT in my `consultsNever`?
2. Write `CONSULT-INBOUND.md` to the session folder with the question + context
3. Write `OUTBOUND.md` with:
```markdown
## Status: needs_consultation
## PartialResult
(what Codex has done/understood so far)
## ConsultationLog
- consulted: researcher
- question: "..."
- status: pending
```
4. End response with `[NEEDS_CONSULTATION]` instead of `[DONE]`
5. Stop โ You will take over from here
## Master Side
When reading OUTBOUND.md after a sub-agent returns:
### STEP 8a โ Detect Consultation Need
If `Status: needs_consultation` is present:
1. Read `ConsultationLog` to get target and question
2. Read `CONSULT-INBOUND.md` for full context
3. Send user update (transparent mode): `[Assistant] โ [{persona} โ {target}] consulting on {topic}...`
4. Proceed to STEP 8b
### STEP 8b โ Run Consultation
```javascript
// Spawn the target sub-identity as a one-shot consultation
sessions_spawn({
model: targetPersonaConfig.model,
task: `You are ${target}.
Read the consultation question from: <path to CONSULT-INBOUND.md>
Write your answer to: <path to CONSULT-OUTBOUND.md>
End with [DONE].`,
label: `shift-consult-${runId}`,
timeoutSeconds: targetPersonaConfig.consultationTimeout
})
```
### STEP 8c โ Feed Result Back
After consultation completes:
1. Read `CONSULT-OUTBOUND.md`
2. Append consultation answer to `CONTEXT.md`:
```markdown
## Consultation Answer from {target}
{answer from CONSULT-OUTBOUND.md}
```
3. Re-spawn the original sub-agent with enriched context:
```javascript
sessions_spawn({
model: originalPersonaConfig.model,
task: `${originalPersonaPrompt}
## Additional Context (from consultation)
The ${target} provided the following guidance:
<answer from CONSULT-OUTBOUND.md>
Continue your task using this context. Write your final result to OUTBOUND.md. End with [DONE].`,
label: `shift-${originalPersona}-consult-continue-${runId}`,
timeoutSeconds: originalPersonaConfig.timeout / 2 // Half remaining time
})
```
### STEP 8d โ Final Result
When re-spawned sub-agent completes:
1. Read final `OUTBOUND.md`
View on GitHub