Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
27 changes: 24 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,9 @@ The setup wizard will guide you through:
3. **Workspace setup** - Name your workspace directory
4. **Default agent** - Configure your main AI assistant
5. **AI provider** - Select Anthropic (Claude) or OpenAI
6. **Model selection** - Choose model (e.g., Sonnet, Opus, GPT-5.3)
7. **Heartbeat interval** - Set proactive check-in frequency
6. **Model selection** - Choose model (e.g., Sonnet, Opus, GPT-5.3, or custom OpenAI-compatible model)
7. **OpenAI endpoint (optional)** - Set custom OpenAI-compatible `base_url` and `api_key`
8. **Heartbeat interval** - Set proactive check-in frequency

<details>
<summary><b>📱 Channel Setup Guides</b></summary>
Expand Down Expand Up @@ -277,7 +278,11 @@ Agents are configured in `.tinyclaw/settings.json`:
"name": "Technical Writer",
"provider": "openai",
"model": "gpt-5.3-codex",
"working_directory": "/Users/me/tinyclaw-workspace/writer"
"working_directory": "/Users/me/tinyclaw-workspace/writer",
"openai": {
"base_url": "https://openrouter.ai/api/v1",
"api_key": "your-api-key"
}
}
}
}
Expand All @@ -289,6 +294,7 @@ Each agent operates in isolation:
- **Own conversation history** - Maintained by CLI
- **Custom configuration** - `.claude/`, `heartbeat.md` (root), `AGENTS.md`
- **Independent resets** - Reset individual agent conversations
- **Optional OpenAI-compatible endpoints** - Set `openai.base_url`/`openai.api_key` per OpenAI agent

<details>
<summary><b>📖 Learn more about agents</b></summary>
Expand Down Expand Up @@ -431,6 +437,21 @@ Located at `.tinyclaw/settings.json`:
}
```

For OpenAI-compatible providers, you can also configure endpoint defaults in `models.openai` (applies to default/fallback agent and as defaults for OpenAI agents):

```json
{
"models": {
"provider": "openai",
"openai": {
"model": "gpt-5.3-codex",
"base_url": "https://openrouter.ai/api/v1",
"api_key": "your-api-key"
}
}
}
```

### Heartbeat Configuration

Edit agent-specific heartbeat prompts:
Expand Down
21 changes: 16 additions & 5 deletions docs/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ Each agent has its own configuration in `.tinyclaw/settings.json`:
"provider": "openai",
"model": "gpt-5.3-codex",
"working_directory": "/Users/me/tinyclaw-workspace/writer",
"openai": {
"base_url": "https://openrouter.ai/api/v1",
"api_key": "your-api-key"
},
"prompt_file": "/path/to/writer-prompt.md"
},
"assistant": {
Expand Down Expand Up @@ -182,13 +186,16 @@ claude --dangerously-skip-permissions \
**OpenAI (Codex):**
```bash
cd "$agent_working_directory" # e.g., ~/tinyclaw-workspace/coder/
OPENAI_BASE_URL="https://openrouter.ai/api/v1" \
OPENAI_API_KEY="your-api-key" \
codex exec resume --last \
--model gpt-5.3-codex \
--skip-git-repo-check \
--dangerously-bypass-approvals-and-sandbox \
--json \
"User message here"
```
`OPENAI_BASE_URL` and `OPENAI_API_KEY` are optional and only used when configured.

## Configuration

Expand All @@ -215,8 +222,8 @@ This walks you through:
1. Agent ID (e.g., `coder`)
2. Display name (e.g., `Code Assistant`)
3. Provider (Anthropic or OpenAI)
4. Model selection
5. Optional system prompt
4. Model selection (including custom OpenAI-compatible model names)
5. Optional OpenAI-compatible endpoint settings (`base_url`, `api_key`) for OpenAI agents

**Working directory is automatically set to:** `<workspace>/<agent_id>/`

Expand Down Expand Up @@ -250,6 +257,8 @@ Edit `.tinyclaw/settings.json`:
| `provider` | Yes | `anthropic` or `openai` |
| `model` | Yes | Model identifier (e.g., `sonnet`, `opus`, `gpt-5.3-codex`) |
| `working_directory` | Yes | Directory where agent operates (auto-set to `<workspace>/<agent_id>/`) |
| `openai.base_url` | No | Optional OpenAI-compatible endpoint base URL for OpenAI agents |
| `openai.api_key` | No | Optional API key exported as `OPENAI_API_KEY` for OpenAI agents |
| `system_prompt` | No | Inline system prompt text |
| `prompt_file` | No | Path to file containing system prompt |

Expand Down Expand Up @@ -428,9 +437,11 @@ If no agents are configured, TinyClaw automatically creates a default agent usin
```json
{
"models": {
"provider": "anthropic",
"anthropic": {
"model": "sonnet"
"provider": "openai",
"openai": {
"model": "gpt-5.3-codex",
"base_url": "https://openrouter.ai/api/v1",
"api_key": "your-api-key"
}
}
}
Expand Down
52 changes: 39 additions & 13 deletions lib/agents.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,13 @@ agent_list() {
echo "================="
echo ""

jq -r '(.agents // {}) | to_entries[] | "\(.key)|\(.value.name)|\(.value.provider)|\(.value.model)|\(.value.working_directory)"' "$SETTINGS_FILE" 2>/dev/null | \
while IFS='|' read -r id name provider model workdir; do
jq -r '(.agents // {}) | to_entries[] | "\(.key)|\(.value.name)|\(.value.provider)|\(.value.model)|\(.value.working_directory)|\(.value.openai.base_url // "")"' "$SETTINGS_FILE" 2>/dev/null | \
while IFS='|' read -r id name provider model workdir openai_base_url; do
echo -e " ${GREEN}@${id}${NC} - ${name}"
echo " Provider: ${provider}/${model}"
if [ -n "$openai_base_url" ]; then
echo " Endpoint: ${openai_base_url}"
fi
echo " Directory: ${workdir}"
echo ""
done
Expand Down Expand Up @@ -115,6 +118,8 @@ agent_add() {

# Model
echo ""
AGENT_OPENAI_BASE_URL=""
AGENT_OPENAI_API_KEY=""
if [ "$AGENT_PROVIDER" = "anthropic" ]; then
echo "Model:"
echo " 1) Sonnet (fast)"
Expand All @@ -128,11 +133,21 @@ agent_add() {
echo "Model:"
echo " 1) GPT-5.3 Codex"
echo " 2) GPT-5.2"
read -rp "Choose [1-2, default: 1]: " AGENT_MODEL_CHOICE
echo " 3) Custom model name"
read -rp "Choose [1-3, default: 1]: " AGENT_MODEL_CHOICE
case "$AGENT_MODEL_CHOICE" in
2) AGENT_MODEL="gpt-5.2" ;;
3)
read -rp "Enter OpenAI-compatible model name: " AGENT_MODEL
if [ -z "$AGENT_MODEL" ]; then
echo -e "${RED}Model name cannot be empty${NC}"
exit 1
fi
;;
*) AGENT_MODEL="gpt-5.3-codex" ;;
esac
read -rp "OpenAI-compatible base URL (optional): " AGENT_OPENAI_BASE_URL
read -rp "OpenAI API key (optional, saved in settings.json): " AGENT_OPENAI_API_KEY
fi

# Working directory - automatically set to agent directory
Expand All @@ -148,12 +163,23 @@ agent_add() {
--arg provider "$AGENT_PROVIDER" \
--arg model "$AGENT_MODEL" \
--arg workdir "$AGENT_WORKDIR" \
--arg base_url "$AGENT_OPENAI_BASE_URL" \
--arg api_key "$AGENT_OPENAI_API_KEY" \
'{
name: $name,
provider: $provider,
model: $model,
working_directory: $workdir
}')
} |
if $provider == "openai" and ($base_url != "" or $api_key != "") then
.openai = (
{}
+ (if $base_url != "" then {base_url: $base_url} else {} end)
+ (if $api_key != "" then {api_key: $api_key} else {} end)
)
else
.
end')

# Ensure agents section exists and add the new agent
jq --arg id "$AGENT_ID" --argjson agent "$agent_json" \
Expand All @@ -171,44 +197,44 @@ agent_add() {
# Copy .claude directory
if [ -d "$SCRIPT_DIR/.claude" ]; then
cp -r "$SCRIPT_DIR/.claude" "$AGENTS_DIR/$AGENT_ID/"
echo " Copied .claude/ to agent directory"
echo " -> Copied .claude/ to agent directory"
else
mkdir -p "$AGENTS_DIR/$AGENT_ID/.claude"
fi

# Copy heartbeat.md
if [ -f "$SCRIPT_DIR/heartbeat.md" ]; then
cp "$SCRIPT_DIR/heartbeat.md" "$AGENTS_DIR/$AGENT_ID/"
echo " Copied heartbeat.md to agent directory"
echo " -> Copied heartbeat.md to agent directory"
fi

# Copy AGENTS.md
if [ -f "$SCRIPT_DIR/AGENTS.md" ]; then
cp "$SCRIPT_DIR/AGENTS.md" "$AGENTS_DIR/$AGENT_ID/"
echo " Copied AGENTS.md to agent directory"
echo " -> Copied AGENTS.md to agent directory"
fi

# Copy AGENTS.md content into .claude/CLAUDE.md as well
if [ -f "$SCRIPT_DIR/AGENTS.md" ]; then
cp "$SCRIPT_DIR/AGENTS.md" "$AGENTS_DIR/$AGENT_ID/.claude/CLAUDE.md"
echo " Copied CLAUDE.md to .claude/ directory"
echo " -> Copied CLAUDE.md to .claude/ directory"
fi

# Symlink skills directory into .claude/skills
if [ -d "$SCRIPT_DIR/.agents/skills" ] && [ ! -e "$AGENTS_DIR/$AGENT_ID/.claude/skills" ]; then
ln -s "$SCRIPT_DIR/.agents/skills" "$AGENTS_DIR/$AGENT_ID/.claude/skills"
echo " Linked skills to .claude/skills/"
echo " -> Linked skills to .claude/skills/"
fi

# Create .tinyclaw directory and copy SOUL.md
mkdir -p "$AGENTS_DIR/$AGENT_ID/.tinyclaw"
if [ -f "$SCRIPT_DIR/SOUL.md" ]; then
cp "$SCRIPT_DIR/SOUL.md" "$AGENTS_DIR/$AGENT_ID/.tinyclaw/SOUL.md"
echo " Copied SOUL.md to .tinyclaw/"
echo " -> Copied SOUL.md to .tinyclaw/"
fi

echo ""
echo -e "${GREEN} Agent '${AGENT_ID}' created!${NC}"
echo -e "${GREEN}[OK] Agent '${AGENT_ID}' created!${NC}"
echo -e " Directory: $AGENTS_DIR/$AGENT_ID"
echo ""
echo -e "${BLUE}Next steps:${NC}"
Expand Down Expand Up @@ -253,7 +279,7 @@ agent_remove() {
rm -rf "$AGENTS_DIR/$agent_id"
fi

echo -e "${GREEN} Agent '${agent_id}' removed.${NC}"
echo -e "${GREEN}[OK] Agent '${agent_id}' removed.${NC}"
}

# Reset a specific agent's conversation
Expand All @@ -279,7 +305,7 @@ agent_reset() {
local agent_name
agent_name=$(jq -r "(.agents // {}).\"${agent_id}\".name" "$SETTINGS_FILE" 2>/dev/null)

echo -e "${GREEN} Reset flag set for agent '${agent_id}' (${agent_name})${NC}"
echo -e "${GREEN}[OK] Reset flag set for agent '${agent_id}' (${agent_name})${NC}"
echo ""
echo "The next message to @${agent_id} will start a fresh conversation."
}
Loading