Skip to content

Commit c45200e

Browse files
ZD Studiosclaude
andcommitted
feat: integrate Fabric (255 patterns) + Caveman (conciseness mode)
Two open-source projects wired in at the prompt level — no extra service to run. FABRIC (danielmiessler/fabric): its 255 patterns are curated system-prompts, so AIOS reads them straight from data/patterns/ and runs them through its OWN model path (llm_chat) — no Go binary needed, and they use whatever provider you set, including the Claude subscription via claude-code. Vendored trimmed to data/ + README + LICENSE (2.2M, dropped ~40M of unused Go/web/docs). New: aios_tools fabric_patterns()/fabric_pattern_system(), hub run_fabric(), 'fabric' chat target, GET+POST /api/fabric, a Patterns dashboard view (filter -> pick -> run), and an inline /p <pattern> <text> chat command. CAVEMAN (JuliusBrussee/caveman): a system-prompt overlay that makes every agent ~65% terser while keeping code/commands/errors verbatim. Read from its own SKILL.md so behaviour + levels (lite/full/ultra/wenyan-*) stay faithful. New: tools.caveman_overlay(), hub caveman state (persisted to .aios/caveman.json) folded into brain_system_prompt(), GET+POST /api/caveman, a composer toggle that cycles off->lite->full->ultra->wenyan, and /caveman [level|off] chat command. Also mounted as a skill into opencode/hermes/openclaw via mount_caveman() so they respect it too. Verified on Windows: 254 patterns load with descriptions, pattern systems resolve, caveman overlay reaches the Brain prompt and toggles on/off, dashboard Patterns + Caveman render with zero console errors, all endpoints respond. The user's running hub on :8787 was left untouched. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent e8082f4 commit c45200e

517 files changed

Lines changed: 44217 additions & 4 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,13 @@ That is deliberately the "ambient authority" posture that made **OpenClaw's CVE-
237237

238238
**Active Memory:** a memory sub-agent runs on **every** turn — recall is a free FTS5 query, fact-extraction is one small async call — so the agents actually learn your workflow over time instead of only reading memory at session start (`memory.active`).
239239

240+
## 🧵 Fabric patterns & 🗿 Caveman mode
241+
242+
Two more open-source projects, wired in at the prompt level (no extra service to run):
243+
244+
- **[Fabric](https://github.com/danielmiessler/fabric) — 255 patterns.** Fabric's "patterns" are curated system-prompts (`summarize`, `extract_wisdom`, `analyze_claims`, `write_essay`, `create_quiz`…). AIOS reads them straight from `data/patterns/` and runs them **on your configured model** — including your Claude subscription — so there's no Go binary to install. Use them in the **Patterns** view (pick → paste → run) or inline in chat: `/p summarize <text>`. The `fabric` chat target also works: `fabric` with a message `pattern: your text`.
245+
- **[Caveman](https://github.com/JuliusBrussee/caveman) — conciseness mode.** A system-prompt overlay that makes every agent ~65% terser while keeping code, commands, and error strings exact. Toggle the **🗿 Caveman** button in the composer (cycles off → lite → full → ultra → wenyan), or type `/caveman [level]` / `/caveman off` in chat. It's also mounted as a skill into opencode/hermes/openclaw, so they respect it too. Levels come straight from Caveman's own SKILL.md.
246+
240247
**On WSL?** `127.0.0.1:8787` often won't reach WSL from your Windows browser (localhost-forwarding is flaky). `aios start`/`aios url` now print your **WSL IP** URL — use that (e.g. `http://172.31.x.x:8787/`). The hub binds `0.0.0.0` so the WSL IP always works.
241248

242249
## ⚙️ Configuration

aios.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,10 @@ def resolve_root(*candidates) -> Path | None:
263263
# openclaw-os is the dashboard for openclaw (not a standalone agent).
264264
"openclaw_os": resolve_root("openclaw-os-main/openclaw-os-main", "openclaw-os-main", "openclaw-os"),
265265
"lifeos": resolve_root("LifeOS-main/LifeOS-main", "LifeOS-main", "LifeOS"),
266+
# Prompt-level integrations (no service): fabric = 255 pattern prompts,
267+
# caveman = a conciseness system-prompt overlay.
268+
"fabric": resolve_root("fabric-main/fabric-main", "fabric-main", "fabric"),
269+
"caveman": resolve_root("caveman-main/caveman-main", "caveman-main", "caveman"),
266270
}
267271

268272

@@ -799,6 +803,7 @@ def cmd_setup(args):
799803
# 6c) mount the bundled AI OS skills (skill-maker, mcp-maker, …) into the agents
800804
if cfg_get(cfg, "skills.mount", True):
801805
mount_aios_skills(cfg)
806+
mount_caveman(cfg) # caveman conciseness skill → every agent
802807

803808
# 7) wire openclaw-os plugin (best-effort; needs openclaw runnable)
804809
if cfg_get(cfg, "services.openclaw_os.enabled", True) and not args.skip_wire:
@@ -1163,6 +1168,30 @@ def mount_aios_skills(cfg: dict):
11631168
ok(f"mounted {len(names)} skills: {', '.join(names)}")
11641169

11651170

1171+
def mount_caveman(cfg: dict):
1172+
"""Mount JuliusBrussee/caveman's skills into every agent, so terser 'caveman
1173+
mode' is available not just to the hub Brain but to opencode/hermes/openclaw too."""
1174+
src = PROJECTS.get("caveman") or (ROOT / "caveman-main")
1175+
skdir = src / "skills"
1176+
if not skdir.exists():
1177+
return
1178+
head("Mounting Caveman skills")
1179+
names = [p.name for p in skdir.iterdir() if p.is_dir() and (p / "SKILL.md").exists()]
1180+
targets = [Path.home() / ".openclaw" / "skills", Path.home() / ".hermes" / "skills",
1181+
STATE / "skills"]
1182+
for t in targets:
1183+
for name in names:
1184+
try:
1185+
dst = t / name
1186+
if dst.exists():
1187+
shutil.rmtree(dst)
1188+
dst.parent.mkdir(parents=True, exist_ok=True)
1189+
shutil.copytree(skdir / name, dst)
1190+
except Exception as e:
1191+
warn(f"could not mount caveman/{name}{t}: {e}")
1192+
ok(f"mounted {len(names)} caveman skills: {', '.join(names)}")
1193+
1194+
11661195
def mount_openui(cfg: dict):
11671196
"""Mount OpenUI (generative-UI) context into every agent's skill dir so any
11681197
agent can respond with OpenUI Lang that the openclaw-os dashboard renders."""

aios_hub.py

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ def read_system_prompt() -> str:
111111

112112

113113
# Chat "targets" the AIOS API exposes as OpenAI-style models.
114-
TARGETS = ["brain", "team", "opencode", "crewai", "claudecode", "all"]
114+
TARGETS = ["brain", "team", "opencode", "crewai", "claudecode", "fabric", "all"]
115115

116116
MEMORY_FILE = ROOT / ".aios" / "memory.json"
117117
USAGE_FILE = ROOT / ".aios" / "usage.json"
@@ -373,6 +373,45 @@ def ask_claudecode(message: str, history: list | None = None) -> str:
373373
return f"⚠️ claude-code-api not reachable ({e}). Start it (`aios start claudecode`) and make sure the `claude` CLI is installed + authenticated."
374374

375375

376+
# --------------------------------------------------------------------------- #
377+
# Caveman mode — a system-prompt overlay (JuliusBrussee/caveman) that makes #
378+
# every agent ~65% terser while keeping technical accuracy. State persists so #
379+
# the toggle survives restarts; levels come from caveman's own SKILL.md. #
380+
# --------------------------------------------------------------------------- #
381+
CAVEMAN_FILE = ROOT / ".aios" / "caveman.json"
382+
383+
384+
def caveman_state() -> dict:
385+
return _load_json(CAVEMAN_FILE, {"enabled": False, "level": "full"})
386+
387+
388+
def set_caveman(enabled: bool, level: str = "full") -> dict:
389+
lvl = level if level in tools.CAVEMAN_LEVELS else "full"
390+
st = {"enabled": bool(enabled), "level": lvl}
391+
_save_json(CAVEMAN_FILE, st)
392+
return st
393+
394+
395+
def caveman_prompt_suffix() -> str:
396+
st = caveman_state()
397+
return tools.caveman_overlay(st["level"]) if st.get("enabled") else ""
398+
399+
400+
# --------------------------------------------------------------------------- #
401+
# Fabric — run any of the 255 danielmiessler/fabric patterns through AIOS's own #
402+
# model path. A pattern is a system prompt; the user's text is the input. #
403+
# --------------------------------------------------------------------------- #
404+
def run_fabric(pattern: str, text: str, target: str = "brain") -> str:
405+
system = tools.fabric_pattern_system(pattern)
406+
if system is None:
407+
return f"⚠️ Unknown fabric pattern '{pattern}'. See the Patterns view for the full list."
408+
system += caveman_prompt_suffix()
409+
# Route through claude-code when the brain is on the subscription, else the LLM.
410+
if target in ("claudecode", "claude-code"):
411+
return ask_claudecode(text, [{"role": "system", "content": system}])
412+
return llm_chat([{"role": "user", "content": text}], system=system)
413+
414+
376415
TOOL_PROTOCOL = (
377416
"\n\nFULL CONTROL: you control the computer AIOS is installed on. To run a shell "
378417
"command, emit a line of exactly this form:\n"
@@ -397,7 +436,8 @@ def brain_system_prompt(message: str) -> str:
397436
"OpenUI-style generative UI (https://www.openui.com).")
398437
if tools.full_control():
399438
sysp += TOOL_PROTOCOL
400-
sysp += active_recall(message) # Active Memory: relevant context, every turn
439+
sysp += active_recall(message) # Active Memory: relevant context, every turn
440+
sysp += caveman_prompt_suffix() # Caveman mode: terser output when toggled on
401441
return sysp
402442

403443

@@ -460,6 +500,12 @@ def route(target: str, message: str, history: list | None = None) -> str:
460500
return ask_opencode(message)
461501
if target in ("claudecode", "claude-code"):
462502
return ask_claudecode(message, history)
503+
if target == "fabric":
504+
# "pattern: text" → run that fabric pattern; else summarize by default.
505+
pat, _, txt = message.partition(":")
506+
if txt.strip():
507+
return run_fabric(pat.strip(), txt.strip())
508+
return run_fabric("summarize", message)
463509
if target in ("team", "auto", "merge"):
464510
return run_team(message, history)
465511
if target == "all":
@@ -1035,6 +1081,10 @@ def do_GET(self):
10351081
self._send(200, {"channels": tools.channels()})
10361082
elif self.path == "/api/skills":
10371083
self._send(200, {"skills": tools.skills(), "learned": brain.skill_list()})
1084+
elif self.path == "/api/fabric":
1085+
self._send(200, {"patterns": tools.fabric_patterns(), "bin": bool(tools.fabric_bin())})
1086+
elif self.path == "/api/caveman":
1087+
self._send(200, {**caveman_state(), "levels": tools.CAVEMAN_LEVELS})
10381088
elif self.path == "/api/tasks":
10391089
self._send(200, {"tasks": brain.task_list()})
10401090
elif self.path == "/api/task_runs":
@@ -1098,6 +1148,27 @@ def do_POST(self):
10981148
target = payload.get("target") or payload.get("to") or "brain"
10991149
message = payload.get("message", "")
11001150
history = payload.get("history", [])
1151+
# Inline commands: /caveman [level|off], /cave …
1152+
cmd = message.strip().lower()
1153+
if cmd.startswith(("/caveman", "/cave")):
1154+
arg = message.strip().split(None, 1)[1].strip().lower() if len(message.split()) > 1 else ""
1155+
if arg in ("off", "stop", "normal"):
1156+
set_caveman(False)
1157+
self._send(200, {"target": target, "reply": "Caveman mode **off** — normal replies.", "ran": []})
1158+
else:
1159+
st = set_caveman(True, arg or caveman_state()["level"])
1160+
self._send(200, {"target": target,
1161+
"reply": f"🗿 Caveman mode **on** · level **{st['level']}**. "
1162+
f"Every agent now replies terse. `/caveman off` to stop.", "ran": []})
1163+
return
1164+
# Inline fabric: /p <pattern> <text> or /pattern <name> <text>
1165+
if cmd.startswith(("/p ", "/pattern ")):
1166+
rest = message.split(None, 1)[1] if len(message.split()) > 1 else ""
1167+
pat, _, txt = rest.partition(" ")
1168+
reply = run_fabric(pat.strip(), txt.strip() or " ".join(m.get("content", "")
1169+
for m in history if m.get("role") == "user")[-4000:])
1170+
self._send(200, {"target": "fabric", "reply": reply, "ran": []})
1171+
return
11011172
reply = route(target, message, history)
11021173
ran = commands_this_turn()
11031174
remember_async(message, reply) # Active Memory: learn from every turn
@@ -1190,6 +1261,13 @@ def do_POST(self):
11901261
payload.get("content", "")))
11911262
else:
11921263
self._send(400, {"error": "unknown op"})
1264+
elif self.path == "/api/fabric":
1265+
out = run_fabric(payload.get("pattern", "summarize"), payload.get("input", ""),
1266+
target=payload.get("target", "brain"))
1267+
self._send(200, {"pattern": payload.get("pattern"), "output": out})
1268+
elif self.path == "/api/caveman":
1269+
st = set_caveman(payload.get("enabled", False), payload.get("level", "full"))
1270+
self._send(200, st)
11931271
elif self.path == "/api/tasks":
11941272
op = payload.get("op", "add")
11951273
if op == "add":

aios_tools.py

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import json
2020
import os
2121
import platform
22+
import shutil
2223
import subprocess
2324
import time
2425
from pathlib import Path
@@ -205,8 +206,107 @@ def learn_skill(name: str, content: str, task: str = "") -> dict:
205206
return {"ok": True, "path": str(d.relative_to(ROOT))}
206207

207208

209+
# --------------------------------------------------------------------------- #
210+
# Fabric — danielmiessler/fabric. Its 255 "patterns" are just system prompts #
211+
# (data/patterns/<name>/system.md), so we run them through AIOS's own LLM path: #
212+
# no Go binary required, and they use whatever model you configured (including #
213+
# your Claude subscription via claude-code). The real `fabric` CLI is optional #
214+
# and only needed for its extras (--serve, youtube, scrape). #
215+
# --------------------------------------------------------------------------- #
216+
_FAB_CACHE: list | None = None
217+
218+
219+
def _fabric_dirs() -> list[Path]:
220+
return [ROOT / "fabric-main" / "data" / "patterns",
221+
Path.home() / ".config" / "fabric" / "patterns"]
222+
223+
224+
def _pattern_desc(system_md: str) -> str:
225+
"""A one-liner for the pattern: the 'You are …' identity line if present."""
226+
for line in system_md.splitlines():
227+
s = line.strip()
228+
if s.lower().startswith(("you are", "you take", "you extract", "you're")):
229+
return s[:200]
230+
for line in system_md.splitlines():
231+
s = line.strip()
232+
if s and not s.startswith("#") and s.upper() not in ("IDENTITY", "INPUT:", "INPUT"):
233+
return s[:200]
234+
return ""
235+
236+
237+
def fabric_patterns() -> list[dict]:
238+
global _FAB_CACHE
239+
if _FAB_CACHE is None:
240+
out, seen = [], set()
241+
for base in _fabric_dirs():
242+
if not base.exists():
243+
continue
244+
for d in sorted(base.iterdir()):
245+
sysf = d / "system.md"
246+
if d.is_dir() and sysf.exists() and d.name not in seen:
247+
seen.add(d.name)
248+
try:
249+
desc = _pattern_desc(sysf.read_text(encoding="utf-8", errors="replace"))
250+
except Exception:
251+
desc = ""
252+
out.append({"name": d.name, "description": desc})
253+
_FAB_CACHE = out
254+
return _FAB_CACHE
255+
256+
257+
def fabric_pattern_system(name: str) -> str | None:
258+
slug = "".join(ch for ch in (name or "").strip().lower() if ch.isalnum() or ch in "-_")
259+
for base in _fabric_dirs():
260+
f = base / slug / "system.md"
261+
if f.exists():
262+
return f.read_text(encoding="utf-8", errors="replace")
263+
return None
264+
265+
266+
def fabric_bin() -> str:
267+
return shutil.which("fabric") or ""
268+
269+
270+
# --------------------------------------------------------------------------- #
271+
# Caveman — JuliusBrussee/caveman. A system-prompt OVERLAY that makes the agent #
272+
# ~65% terser while keeping technical accuracy. We read its own SKILL.md so the #
273+
# behaviour stays faithful, and expose the intensity levels it defines. #
274+
# --------------------------------------------------------------------------- #
275+
CAVEMAN_LEVELS = ["lite", "full", "ultra", "wenyan-lite", "wenyan-full", "wenyan-ultra"]
276+
277+
_CAVE_FALLBACK = (
278+
"Respond terse like smart caveman. All technical substance stays; only fluff dies. "
279+
"Drop articles (a/an/the), filler (just/really/basically), pleasantries, hedging. "
280+
"Fragments OK. Short synonyms. No tool-call narration, no decorative tables/emoji. "
281+
"Keep technical terms, code, API names, CLI commands and exact error strings verbatim. "
282+
"Never invent abbreviations. Never announce the style.")
283+
284+
285+
def caveman_skill() -> str:
286+
f = ROOT / "caveman-main" / "skills" / "caveman" / "SKILL.md"
287+
if f.exists():
288+
txt = f.read_text(encoding="utf-8", errors="replace")
289+
# Strip the YAML front-matter; keep the behavioural body.
290+
if txt.startswith("---"):
291+
end = txt.find("---", 3)
292+
if end > 0:
293+
txt = txt[end + 3:].strip()
294+
return txt
295+
return _CAVE_FALLBACK
296+
297+
298+
def caveman_overlay(level: str = "full") -> str:
299+
level = level if level in CAVEMAN_LEVELS else "full"
300+
return (f"\n\n## CAVEMAN MODE — intensity: {level}\n"
301+
"Apply this output style to every reply from now on (compress the STYLE, not the "
302+
"content; keep code, commands, API names and error strings exact):\n\n"
303+
+ caveman_skill())
304+
305+
208306
if __name__ == "__main__":
209307
print(json.dumps({"full_control": full_control(), "guardrails": guardrails_on(),
210-
"channels": len(channels()), "skills": len(skills())}, indent=2))
308+
"channels": len(channels()), "skills": len(skills()),
309+
"fabric_patterns": len(fabric_patterns()), "fabric_bin": fabric_bin() or None,
310+
"caveman": bool(caveman_skill())}, indent=2))
211311
for c in channels():
212312
print(f" {'[x]' if c['configured'] else '[ ]'} {c['id']:<20} {c['blurb'][:60]}")
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
3+
"name": "caveman",
4+
"description": "Ultra-compressed communication mode for Claude Code. Cuts 65% of output tokens (measured) while keeping full technical accuracy.",
5+
"owner": {
6+
"name": "Julius Brussee",
7+
"url": "https://github.com/JuliusBrussee"
8+
},
9+
"plugins": [
10+
{
11+
"name": "caveman",
12+
"description": "Talk like caveman. Cut 65% output tokens (measured). Keep all technical accuracy.",
13+
"source": "./",
14+
"category": "productivity"
15+
}
16+
]
17+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"name": "caveman",
3+
"description": "Ultra-compressed communication mode. Cuts 65% of output tokens (measured) while keeping full technical accuracy by speaking like a caveman.",
4+
"author": {
5+
"name": "Julius Brussee",
6+
"url": "https://github.com/JuliusBrussee"
7+
},
8+
"hooks": {
9+
"SessionStart": [
10+
{
11+
"hooks": [
12+
{
13+
"type": "command",
14+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/src/hooks/caveman-activate.js\"",
15+
"timeout": 5,
16+
"statusMessage": "Loading caveman mode..."
17+
}
18+
]
19+
}
20+
],
21+
"UserPromptSubmit": [
22+
{
23+
"hooks": [
24+
{
25+
"type": "command",
26+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/src/hooks/caveman-mode-tracker.js\"",
27+
"timeout": 5,
28+
"statusMessage": "Tracking caveman mode..."
29+
}
30+
]
31+
}
32+
]
33+
}
34+
}

caveman-main/.codex/config.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[features]
2+
hooks = true

caveman-main/.codex/hooks.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"hooks": {
3+
"SessionStart": [
4+
{
5+
"matcher": "startup|resume",
6+
"hooks": [
7+
{
8+
"type": "command",
9+
"command": "echo 'CAVEMAN MODE ACTIVE. Rules: Drop articles/filler/pleasantries/hedging. Fragments OK. Short synonyms. Pattern: [thing] [action] [reason]. [next step]. Not: Sure! I would be happy to help you with that. Yes: Bug in auth middleware. Fix: Code/commits/security: write normal. User says stop caveman or normal mode to deactivate.'",
10+
"timeout": 5,
11+
"statusMessage": "Loading caveman mode"
12+
}
13+
]
14+
}
15+
]
16+
}
17+
}

caveman-main/.editorconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
root = true
2+
3+
[*]
4+
indent_style = space
5+
indent_size = 2
6+
end_of_line = lf
7+
charset = utf-8
8+
trim_trailing_whitespace = true
9+
insert_final_newline = true

caveman-main/.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto

0 commit comments

Comments
 (0)