You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CLAUDE.md
+94-25Lines changed: 94 additions & 25 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# Bareclaw — CLAUDE.md
2
2
3
-
Self-hosted AI agent platform. Local Ollama LLM (optional OpenAI) exposed via web UI, Telegram, webhooks, and cron jobs. Single asyncio event loop runs all subsystems concurrently.
3
+
Self-hosted AI agent platform. Local Ollama LLM (optional OpenAI) exposed via web UI, Telegram, webhooks, and deterministic scheduled jobs. Single asyncio event loop runs all subsystems concurrently.
4
4
5
5
## Running
6
6
@@ -13,7 +13,28 @@ python main.py
13
13
14
14
No test suite. Verify changes by running the app and exercising the affected interface.
15
15
16
-
## Docker
16
+
## Deployment
17
+
18
+
### Systemd (bare-metal)
19
+
20
+
Runs as a systemd user service — agents have direct access to the host filesystem within their configured workspace.
21
+
22
+
```bash
23
+
mkdir -p ~/.config/systemd/user
24
+
cp bareclaw.service ~/.config/systemd/user/
25
+
systemctl --user daemon-reload
26
+
systemctl --user enable --now bareclaw
27
+
journalctl --user -u bareclaw -f
28
+
```
29
+
30
+
To keep running at boot without a login session, a sudoer must run once:
31
+
```bash
32
+
sudo loginctl enable-linger bareclaw
33
+
```
34
+
35
+
### Docker
36
+
37
+
Agent file access is limited to volumes explicitly mounted into the container. To expose additional host paths, add volume mounts to `docker-compose.yml` and update the agent's `workspace:`.
└── scheduler (APScheduler) # cron jobs → project tasks or commands → optional Telegram notify
48
69
└── telegram bot (optional)
49
70
```
50
71
51
72
**Agentic loop** (`bareclaw/core/agent.py`): system prompt + messages → LLM → if tool_calls → dispatch → loop; capped by `max_iterations`.
52
73
53
-
**Multi-provider LLM** (`bareclaw/core/llm.py`): `OllamaClient` and `OpenAIClient` both normalise to the same canonical message dict. `config.providers` is a named map; `main.py` builds one client per provider at startup. `agent.py` is provider-agnostic — it looks up `clients[agent.provider]` by id. Any number of Ollama instances, OpenAI-compatible servers (LM Studio, vLLM, llama.cpp), or the real OpenAI API can be configured simultaneously.
74
+
**Multi-provider LLM** (`bareclaw/core/llm.py`): `OllamaClient` and `OpenAIClient` both normalise to the same canonical message dict. `config.providers` is a named map; `main.py` builds one client per provider at startup. `agent.py` is provider-agnostic — it looks up `clients[agent.provider]` by id. Any number of Ollama instances, OpenAI-compatible servers (LM Studio, vLLM, llama.cpp, OpenRouter.ai), or the real OpenAI API can be configured simultaneously.
command: "df -h"# optional; output prepended to prompt
99
-
prompt: "Analyse the above and alert if ..."
122
+
project: my-project
123
+
task: check-system
100
124
notify_telegram: false
101
125
```
102
126
127
+
Exactly one target must be defined per cron job:
128
+
- `project` + `task` for a scheduled project task
129
+
- `command`for an explicit shell command, optionally with `workspace` and `timeout`
130
+
131
+
Command example:
132
+
```yaml
133
+
id: disk-check
134
+
schedule: "0 * * * *"
135
+
command: "df -h"
136
+
workspace: ~/workspace
137
+
timeout: 30
138
+
notify_telegram: true
139
+
```
140
+
141
+
Project-task crons resolve the referenced task directly in Python and run that task prompt using `task.agent → project.agent → config.default_agent`. Command crons execute the configured shell command directly. Cron jobs do not self-call the HTTP API.
The filename must match the superpower `id`. Consider `chmod 600 secrets/<id>.yaml`.
207
+
The filename must match the superpower `id`. Consider `chmod 600 secrets/<id>.env`.
168
208
169
-
**Auto-injection**: `_build_system_content()` in `bareclaw/core/agent.py` keyword-matches user messages against all superpowers and appends matching ones (including secrets) to the system prompt under `## Available superpowers`.
209
+
**Auto-injection**: `_build_system_content()` in `bareclaw/core/agent.py` keyword-matches user messages against all superpowers and appends matching ones to the system prompt under `## Available superpowers`. Config values are shown; secrets are represented as the file path + variable names only (values never enter LLM context). Example injection:
The agent uses `run_command` to source the file: `source /path/to/secrets/homeassistant.env && curl -H "Authorization: Bearer $token" ...`
214
+
215
+
**Bootstrap**: clicking "Bootstrap Memory" in the `/superpowers` UI POSTs to `/api/superpowers/{id}/bootstrap`. The server interpolates `{key}` placeholders in `bootstrap_prompt` with merged config+secrets values, then runs the bootstrap agent. The agent typically uses `run_command` (curl) + `write_memory` to document findings.
170
216
171
-
**Bootstrap**: clicking Bootstrap in the `/superpowers` UI POSTs to `/api/superpowers/{id}/bootstrap`. The server interpolates `{key}` placeholders in `bootstrap_prompt` with merged config+secrets values, then runs the bootstrap agent. The agent typically uses `run_command` (curl) + `write_memory` to document findings.
217
+
**Provider API keys** also use `.env` format — `secrets/<provider-id>.env` with `api_key=sk-...`. Loaded by Python at startup; the LLM never sees them.
172
218
173
219
**Tools** (always available to all agents — no YAML config needed):
174
220
- `list_superpowers` — returns id, name, description, keywords for all superpowers
175
-
- `read_superpower(id)`— returns full config + secrets so the agent can use them
`superpowers/example.yaml`and `secrets/example.yaml` are committed to git; all other files in both dirs are gitignored. Both dirs are mounted as volumes in Docker.
223
+
`superpowers/example.yaml` and `secrets/example.env` are committed to git; all other files in both dirs are gitignored. Both dirs are mounted as volumes in Docker.
Multi-component workflows the agent has explored and can execute. Each project defines named **tasks** — runnable prompts triggerable from the `/projects` UI or by agents via tools. Loaded fresh on each agent call (no restart needed). Safe to commit (no secrets).
229
+
Multi-component workflows the agent has explored and can execute. Each project defines named **tasks** — runnable prompts triggerable from the `/projects` UI, by cron schedules, or by agents via tools. Loaded fresh on each agent call (no restart needed). Safe to commit (no secrets).
184
230
185
231
```yaml
186
232
id: home-network-security
@@ -191,9 +237,9 @@ keywords:
191
237
- pcap
192
238
- network security
193
239
agent: default # default agent for tasks; falls back to config.default_agent
194
-
memories: # related memory IDs shown in UI and injected into system prompt
195
-
- home-network-architecture
196
-
- pcap-pipeline-process
240
+
memories: # auto-injected into task context when tasks execute
241
+
- home-network-security-runbook
242
+
- home-network-troubleshooting
197
243
tasks:
198
244
- id: run-pipeline
199
245
name: "Run Pipeline"
@@ -206,19 +252,42 @@ tasks:
206
252
prompt: |
207
253
Check the security dashboard for anomalies in the last 24 hours.
208
254
agent: "" # optional per-task agent override
255
+
bootstrap_prompt: |
256
+
You are bootstrapping the project "{name}" (ID: {id}).
257
+
258
+
Description: {description}
259
+
260
+
Available tasks: {tasks}
261
+
262
+
Your goal is to RUN these tasks and document practical operational knowledge.
263
+
Create a memory called '{id}-runbook' using write_memory with execution flow,
264
+
file locations, dependencies, timing, and troubleshooting tips.
265
+
bootstrap_agent: "" # optional; defaults to project.agent or config.default_agent
209
266
```
210
267
211
-
**Auto-injection**: `_build_system_content()` keyword-matches user messages against all projects and appends matching ones under `## Relevant projects`, including task summaries and referenced memory IDs.
268
+
**Auto-injection (chat context)**: `_build_system_content()` keyword-matches user messages against all projects and appends matching ones under `## Relevant projects`, including task summaries and referenced memory IDs.
269
+
270
+
**Auto-injection (task execution)**: When a task runs via `run_project_task()` in `bareclaw/core/task_runner.py`, all memories listed in the project's `memories:` field are automatically loaded and injected into the task's user prompt under `## Project Knowledge`. This means:
271
+
- Tasks always have access to the project's operational knowledge (runbooks, troubleshooting guides)
272
+
- No need for agents to explicitly call `read_memory()`
273
+
- Cron jobs get the same context as manual runs
274
+
275
+
**Task execution**: clicking Run in the `/projects` UI POSTs to `/api/projects/{id}/tasks/{task_id}/run`. Cron jobs also resolve tasks by `project` + `task` and run the same prompt path. Agent resolved as `task.agent → project.agent → config.default_agent`.
276
+
277
+
**Bootstrap**: clicking "Bootstrap Runbook" in the `/projects` UI POSTs to `/api/projects/{id}/bootstrap`. The server interpolates `{key}` placeholders in `bootstrap_prompt` (available: `{id}`, `{name}`, `{description}`, `{agent}`, `{memories}`, `{tasks}`) using `proj_mod.interpolate()`, then runs the bootstrap agent. The agent typically executes tasks using available tools and uses `write_memory` to create a `{id}-runbook` memory.
212
278
213
-
**Task execution**: clicking Run in the `/projects` UI POSTs to `/api/projects/{id}/tasks/{task_id}/run`. Agent resolved as `task.agent → project.agent → config.default_agent`.
279
+
The Bootstrap Runbook button:
280
+
- Only appears if `bootstrap_prompt` is defined
281
+
- Hides automatically once `memories/{id}-runbook.yaml` exists (checked via `proj_mod.has_runbook()`)
282
+
- Reappears if the runbook memory is deleted
214
283
215
284
**Tools** (always available to all agents — no YAML config needed):
216
285
-`list_projects` — returns id, name, description for all projects
217
286
-`read_project(id)` — returns full project details including tasks and prompts
218
287
219
288
`projects/example.yaml` is the only project file committed to git; all others are gitignored.
0 commit comments