Adding a Boutique
A boutique is a folder in groups/ with at minimum a CLAUDE.md file. This page covers adding one to a running ique.bot instance.
Quick Version
# 1. Create the folder
mkdir -p groups/my-boutique
# 2. Write the persona
cat > groups/my-boutique/CLAUDE.md << 'EOF'
# My Boutique
You are My Boutique. You help with X.
## Hard Rules
1. Never do Y.
2. Always respond in JSON.
EOF
# 3. Register in the database
node -e "
const { DatabaseSync } = require('node:sqlite');
const db = new DatabaseSync('ique/ique.db');
db.exec(\"INSERT OR IGNORE INTO boutiques (boutique_id, display_name, status, description) VALUES ('my-boutique', 'My Boutique', 'active', 'Helps with X tasks.')\");
db.close();
"
# 4. Add to start.sh (or run standalone)
# Edit ique/start.sh and add:
# npx tsx ique/worker.ts & (with BOUTIQUE_ID=my-boutique)
# 5. Restart
./ique/start.shDetailed Steps
1. Create the Group Folder
mkdir -p groups/my-boutiqueThe folder name becomes the boutique_id. Use lowercase with hyphens.
2. Write CLAUDE.md
This is the system prompt the LLM receives on every task. It should include:
- Identity — who is this worker?
- Objectives — what does it do? (3-5 bullet points)
- Hard rules — what must it never do?
- Output format — JSON? Markdown? Plain text?
- Domain constraints — budget limits, exclusions, safety rules
See Boutique Authoring for detailed guidance.
3. Register the Boutique
The router needs to know about your boutique. Add it to the boutiques table.
For fresh installs, add to ique/setup.sql:
INSERT OR IGNORE INTO boutiques (boutique_id, display_name, status, description)
VALUES ('my-boutique', 'My Boutique', 'active',
'One-sentence description of what this boutique handles.');For an existing database, run the INSERT directly:
node -e "
const { DatabaseSync } = require('node:sqlite');
const db = new DatabaseSync('ique/ique.db');
db.exec(\"INSERT OR IGNORE INTO boutiques (boutique_id, display_name, status, description) VALUES ('my-boutique', 'My Boutique', 'active', 'Description here.')\");
db.close();
"The description field matters — it's what the semantic router (Tier 2) reads when deciding where to send free-form messages.
4. Add Slash Commands (Optional)
In ique/router.ts, add entries to FAST_PASS_ROUTES:
"/myboutique": "my-boutique",And keyword fallback entries:
"my-boutique": ["keyword1", "keyword2", "relevant phrase"],5. Choose a Worker Type
Generic worker — no custom code. Uses the CLAUDE.md as the system prompt and passes the user's message to the LLM:
BOUTIQUE_ID=my-boutique npx tsx ique/worker.tsCustom worker — write groups/my-boutique/worker.ts with domain-specific fetch-then-reason logic. Copy groups/radar/worker.ts as a starting template.
6. Add to start.sh
For the generic worker:
BOUTIQUE_ID=my-boutique npx tsx ique/worker.ts &
PIDS+=($!)For a custom worker:
npx tsx groups/my-boutique/worker.ts &
PIDS+=($!)7. Restart and Test
# Ctrl+C the running stack
./ique/start.shThen message your bot with the slash command or a free-form message that matches your boutique's description.
Verify It's Working
Check the boutiques table:
node -e "
const { DatabaseSync } = require('node:sqlite');
const db = new DatabaseSync('ique/ique.db');
console.log(db.prepare('SELECT boutique_id, status FROM boutiques').all());
db.close();
"Check the queue for your boutique's tasks:
node -e "
const { DatabaseSync } = require('node:sqlite');
const db = new DatabaseSync('ique/ique.db');
console.log(db.prepare(\"SELECT task_id, status, assigned_boutique FROM ique_queue WHERE assigned_boutique = 'my-boutique' ORDER BY created_at DESC LIMIT 5\").all());
db.close();
"