create-ironclaws 1.0.0 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@ USER root
|
|
|
11
11
|
|
|
12
12
|
# Python 3 + pip (requests needed by elastic_query.py)
|
|
13
13
|
RUN apt-get update && apt-get install -y python3 python3-pip && rm -rf /var/lib/apt/lists/*
|
|
14
|
-
RUN pip3 install requests youtube-transcript-api markdownify --break-system-packages
|
|
14
|
+
RUN pip3 install requests tenacity youtube-transcript-api markdownify --break-system-packages
|
|
15
15
|
|
|
16
16
|
# Poetry
|
|
17
17
|
RUN pip3 install poetry --break-system-packages
|
|
@@ -1,92 +1,233 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: slack-formatting
|
|
3
|
-
description: Format messages for Slack using mrkdwn
|
|
3
|
+
description: Format messages for Slack using mrkdwn. All agents in this deployment communicate via Slack — these rules always apply.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Slack
|
|
6
|
+
# Slack Formatting — World-Class Messages
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Every message you send goes to Slack. Slack does not render standard Markdown. Follow these rules exactly.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## The Golden Rules
|
|
13
|
+
|
|
14
|
+
1. `*bold*` — never `**bold**`
|
|
15
|
+
2. `_italic_` — never `*italic*`
|
|
16
|
+
3. No markdown tables — never `| col | col |`
|
|
17
|
+
4. No `##` headings — use `*Bold text*` instead
|
|
18
|
+
5. No `---` horizontal rules
|
|
19
|
+
6. No `[text](url)` — use `<url|text>` instead
|
|
20
|
+
7. Email drafts and code always go in ` ```triple backtick blocks``` `
|
|
21
|
+
8. Emoji add clarity — use them intentionally, not decoratively
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## RAG Status Emoji — Exact Codes (memorise these)
|
|
26
|
+
|
|
27
|
+
These are the ONLY correct codes for traffic-light status indicators. Do not guess or vary them.
|
|
28
|
+
|
|
29
|
+
| Status | Correct code | Wrong codes (do not use) |
|
|
30
|
+
|--------|-------------|--------------------------|
|
|
31
|
+
| 🔴 Red / violation / critical | `:red_circle:` | ~~`:large_red_circle:`~~ |
|
|
32
|
+
| 🟡 Yellow / warning / caution | `:large_yellow_circle:` | ~~`:yellow_circle:`~~ ~~`:warning:`~~ |
|
|
33
|
+
| 🟢 Green / compliant / clean | `:large_green_circle:` | ~~`:green_circle:`~~ ~~`:white_check_mark:`~~ |
|
|
34
|
+
|
|
35
|
+
Rule: red has no `large_` prefix. Yellow and green both require the `large_` prefix. This is a Slack quirk — the non-large versions of yellow and green render as different emoji entirely.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Data without tables
|
|
40
|
+
|
|
41
|
+
Tables don't render. Use these patterns instead:
|
|
42
|
+
|
|
43
|
+
**Field list (best for structured data):**
|
|
44
|
+
```
|
|
45
|
+
*Voucher:* AP-818
|
|
46
|
+
*Vendor:* Metosin Oy
|
|
47
|
+
*Amount:* 325,994.74 NOK
|
|
48
|
+
*Posted:* 2025-08-31
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Compact inline (best for short summaries):**
|
|
52
|
+
```
|
|
53
|
+
AP-818 • Metosin Oy • 325,994.74 NOK • 2025-08-31
|
|
54
|
+
```
|
|
11
55
|
|
|
12
|
-
|
|
56
|
+
**Key-value in code block (best for exact copy-paste, e.g. email drafts):**
|
|
57
|
+
````
|
|
58
|
+
```
|
|
59
|
+
Voucher: AP-818
|
|
60
|
+
Vendor: Metosin Oy
|
|
61
|
+
Amount: 325,994.74 NOK
|
|
62
|
+
Move from: 6784 – Konsulentkostnader Utvikling
|
|
63
|
+
Move to: [INSERT ACCOUNT]
|
|
64
|
+
```
|
|
65
|
+
````
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Message structure
|
|
70
|
+
|
|
71
|
+
**Use blank lines to breathe.** Dense walls of text are hard to scan on mobile.
|
|
72
|
+
|
|
73
|
+
**Sections flow like this:**
|
|
74
|
+
```
|
|
75
|
+
*Title or status line*
|
|
76
|
+
|
|
77
|
+
Short one-line context sentence.
|
|
78
|
+
|
|
79
|
+
:emoji: *Section header*
|
|
80
|
+
Content here
|
|
81
|
+
|
|
82
|
+
:emoji: *Another section*
|
|
83
|
+
Content here
|
|
84
|
+
|
|
85
|
+
> Callout or note for important info
|
|
86
|
+
|
|
87
|
+
_Footer — instructions or next steps_
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Violations and alerts
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
:red_circle: *1 violation found — action required*
|
|
13
96
|
|
|
14
|
-
|
|
97
|
+
*Voucher:* AP-818
|
|
98
|
+
*Vendor:* Metosin Oy (Finland)
|
|
99
|
+
*Amount:* 325,994.74 NOK
|
|
100
|
+
*Posted:* 2025-08-31
|
|
101
|
+
*Issue:* Vendor invoice posted to 6784 — must be reclassified by Amesto
|
|
15
102
|
|
|
16
|
-
|
|
103
|
+
> Christian — fill in `[INSERT ACCOUNT]` and send the correction email below.
|
|
104
|
+
```
|
|
17
105
|
|
|
18
|
-
|
|
19
|
-
|-------|--------|---------|
|
|
20
|
-
| Bold | `*text*` | *bold text* |
|
|
21
|
-
| Italic | `_text_` | _italic text_ |
|
|
22
|
-
| Strikethrough | `~text~` | ~strikethrough~ |
|
|
23
|
-
| Code (inline) | `` `code` `` | `inline code` |
|
|
24
|
-
| Code block | ` ```code``` ` | Multi-line code |
|
|
106
|
+
---
|
|
25
107
|
|
|
26
|
-
|
|
108
|
+
## Status summaries
|
|
27
109
|
|
|
28
110
|
```
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
<!channel> # @channel
|
|
111
|
+
:white_check_mark: *Expense check complete — May 2026*
|
|
112
|
+
|
|
113
|
+
• Reports checked: 14 | Expenses: 67
|
|
114
|
+
• :red_circle: 2 red violations | :large_yellow_circle: 7 yellow flags
|
|
115
|
+
• Notifications: 0 (DM sending not yet enabled)
|
|
35
116
|
```
|
|
36
117
|
|
|
37
|
-
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Email and document drafts
|
|
38
121
|
|
|
39
|
-
|
|
122
|
+
Always use a triple-backtick code block. This makes it copy-paste ready and visually distinct:
|
|
123
|
+
|
|
124
|
+
````
|
|
125
|
+
Here's the correction email for Christian to review and send:
|
|
40
126
|
|
|
41
127
|
```
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
128
|
+
To: [Amesto contact]
|
|
129
|
+
Cc: finance@ardoq.com, Christian Dotterweich <christian.dotterweich@ardoq.com>
|
|
130
|
+
Subject: Correction request — voucher AP-818 — move from 6784 to [INSERT ACCOUNT]
|
|
131
|
+
|
|
132
|
+
Hi [Amesto contact],
|
|
133
|
+
|
|
134
|
+
Please reclassify the following vendor invoice ...
|
|
135
|
+
|
|
136
|
+
Voucher: AP-818
|
|
137
|
+
Vendor: Metosin Oy
|
|
138
|
+
Amount: 325,994.74 NOK
|
|
139
|
+
Move from: 6784 – Konsulentkostnader Utvikling
|
|
140
|
+
Move to: [INSERT ACCOUNT]
|
|
141
|
+
|
|
142
|
+
Thanks,
|
|
143
|
+
Christian Dotterweich
|
|
45
144
|
```
|
|
145
|
+
````
|
|
46
146
|
|
|
47
|
-
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Progress updates (mid-run)
|
|
48
150
|
|
|
49
|
-
|
|
151
|
+
Use `send_message` for long-running tasks so people know you're working:
|
|
50
152
|
|
|
51
153
|
```
|
|
52
|
-
|
|
53
|
-
|
|
154
|
+
:hourglass_flowing_sand: Fetching transactions from Xledger...
|
|
155
|
+
```
|
|
156
|
+
```
|
|
157
|
+
:mag: Found 3 entries on account 6784 — running classification...
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Escalations and warnings
|
|
163
|
+
|
|
54
164
|
```
|
|
165
|
+
:rotating_light: *Annual true-up required — December close*
|
|
55
166
|
|
|
56
|
-
|
|
167
|
+
The December close report cannot be marked complete until the annual true-up is logged.
|
|
57
168
|
|
|
58
|
-
|
|
169
|
+
Reply with:
|
|
170
|
+
`annual true-up done 2025: <summary including adjustment amount>`
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
59
174
|
|
|
60
|
-
##
|
|
175
|
+
## Confirmations and success
|
|
61
176
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
- **NO** `1.` numbered lists (use bullets with numbers: `• 1. First`)
|
|
66
|
-
- **NO** tables (use code blocks or plain text alignment)
|
|
67
|
-
- **NO** `---` horizontal rules
|
|
177
|
+
```
|
|
178
|
+
:white_check_mark: *Done* — session flagged as resolved in state/flagged_6784.json
|
|
179
|
+
```
|
|
68
180
|
|
|
69
|
-
|
|
181
|
+
```
|
|
182
|
+
:white_check_mark: *Reconciliation complete — 6784 — 2025-08*
|
|
70
183
|
|
|
184
|
+
:red_circle: 1 violation | :large_green_circle: 1 compliant | no volume flag
|
|
71
185
|
```
|
|
72
|
-
*Daily Standup Summary*
|
|
73
186
|
|
|
74
|
-
|
|
187
|
+
---
|
|
75
188
|
|
|
76
|
-
|
|
77
|
-
• *In Progress:* Building new dashboard widgets
|
|
78
|
-
• *Blocked:* Waiting on API access from DevOps
|
|
189
|
+
## Lists
|
|
79
190
|
|
|
80
|
-
|
|
191
|
+
Use `•` for bullets. Never `1.` numbered lists (they don't render as lists in Slack):
|
|
81
192
|
|
|
82
|
-
:white_check_mark: All tests passing | <https://ci.example.com/builds/123|View Build>
|
|
83
193
|
```
|
|
194
|
+
What was checked:
|
|
195
|
+
• Account 6784 — Konsulentkostnader Utvikling
|
|
196
|
+
• Period: 2025-08 (August)
|
|
197
|
+
• Source: Xledger GraphQL API
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
---
|
|
84
201
|
|
|
85
|
-
##
|
|
202
|
+
## Mentions and links
|
|
203
|
+
|
|
204
|
+
```
|
|
205
|
+
<@U04S2VA1CU8> # Mention a specific user
|
|
206
|
+
<#C0B36KNFDHV|finance-close-ops> # Link a channel
|
|
207
|
+
<https://expensify.com/report?id=123|View report> # Named link
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Dividers and spacing
|
|
213
|
+
|
|
214
|
+
Never use `---`. Use blank lines between sections. For a hard visual break, use a line of spaces or just let the sections breathe naturally.
|
|
215
|
+
|
|
216
|
+
---
|
|
86
217
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
218
|
+
## Quick cheat sheet
|
|
219
|
+
|
|
220
|
+
| Goal | Use |
|
|
221
|
+
|------|-----|
|
|
222
|
+
| Bold | `*text*` |
|
|
223
|
+
| Italic | `_text_` |
|
|
224
|
+
| Code inline | `` `code` `` |
|
|
225
|
+
| Code block | ` ```block``` ` |
|
|
226
|
+
| Bullet | `•` |
|
|
227
|
+
| Blockquote | `> text` |
|
|
228
|
+
| Link | `<url\|text>` |
|
|
229
|
+
| Mention user | `<@USERID>` |
|
|
230
|
+
| Emoji | `:white_check_mark:` |
|
|
231
|
+
| "Heading" | `*Bold line*` then blank line |
|
|
232
|
+
| Table | Field list or code block |
|
|
233
|
+
| Divider | Blank line |
|
|
@@ -4,6 +4,8 @@ You are Forge, the built-in guide for IronClaws. You help people understand how
|
|
|
4
4
|
|
|
5
5
|
You are running inside IronClaws itself — which means you can inspect the codebase, read configuration files, and help make changes directly.
|
|
6
6
|
|
|
7
|
+
**You communicate exclusively through Slack. Always use Slack mrkdwn formatting — never standard Markdown. Follow the `slack-formatting` skill for every message you send. Key rules: `*bold*` not `**bold**`, no `##` headings, no markdown tables, no `---` dividers.**
|
|
8
|
+
|
|
7
9
|
---
|
|
8
10
|
|
|
9
11
|
## What you know
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
# Run this on the VM after deploying NanoClaw:
|
|
8
8
|
# cd ~/nanoclaw-docker && bash scripts/setup-onecli-secrets.sh
|
|
9
9
|
|
|
10
|
-
set -
|
|
10
|
+
set -eo pipefail
|
|
11
11
|
|
|
12
12
|
ENV_FILE="${ENV_FILE:-$(dirname "$0")/../.env}"
|
|
13
13
|
API="http://localhost:10254"
|
|
@@ -112,6 +112,13 @@ if [ ! -f "$ENV_FILE" ]; then
|
|
|
112
112
|
exit 1
|
|
113
113
|
fi
|
|
114
114
|
|
|
115
|
+
# Check OneCLI is reachable before proceeding
|
|
116
|
+
if ! api_curl "$API/api/secrets" > /dev/null 2>&1; then
|
|
117
|
+
echo " ⚠ OneCLI not reachable at $API — skipping secrets setup"
|
|
118
|
+
echo " Start OneCLI with: docker compose up -d"
|
|
119
|
+
exit 0
|
|
120
|
+
fi
|
|
121
|
+
|
|
115
122
|
echo "Reading credentials from $ENV_FILE"
|
|
116
123
|
echo ""
|
|
117
124
|
|
|
@@ -135,6 +142,13 @@ CONFLUENCE_BASIC=$(printf '%s:%s' "$CONFLUENCE_USERNAME" "$CONFLUENCE_PASSWORD"
|
|
|
135
142
|
SLACK_BOT_TOKEN=$(env_val "SLACK_BOT_TOKEN")
|
|
136
143
|
INTERCOM_ACCESS_TOKEN=$(env_val "INTERCOM_ACCESS_TOKEN")
|
|
137
144
|
|
|
145
|
+
XLEDGER_API_TOKEN=$(env_val "XLEDGER_API_TOKEN")
|
|
146
|
+
XLEDGER_API_BASE=$(env_val "XLEDGER_API_BASE")
|
|
147
|
+
XLEDGER_HOST=$(echo "$XLEDGER_API_BASE" | sed 's|^https://||;s|^http://||' | cut -d/ -f1)
|
|
148
|
+
|
|
149
|
+
ARDOQ_API_KEY=$(env_val "ARDOQ_API_KEY")
|
|
150
|
+
ARDOQ_BASE_URL=$(env_val "ARDOQ_BASE_URL")
|
|
151
|
+
ARDOQ_HOST=$(echo "$ARDOQ_BASE_URL" | sed 's|^https://||;s|^http://||' | cut -d/ -f1)
|
|
138
152
|
|
|
139
153
|
ANTHROPIC_AUTH_TOKEN=$(env_val "ANTHROPIC_AUTH_TOKEN")
|
|
140
154
|
LLM_GATEWAY=$(env_val "ANTHROPIC_BASE_URL")
|
|
@@ -168,11 +182,18 @@ fi
|
|
|
168
182
|
upsert_secret "intercom" "api.intercom.io" "Authorization" "Bearer $INTERCOM_ACCESS_TOKEN" || \
|
|
169
183
|
echo " ⚠ Skipping intercom"
|
|
170
184
|
|
|
185
|
+
[ -n "$ARDOQ_API_KEY" ] && [ -n "$ARDOQ_HOST" ] && \
|
|
186
|
+
upsert_secret "ardoq" "$ARDOQ_HOST" "Authorization" "Token token=$ARDOQ_API_KEY" || \
|
|
187
|
+
echo " ⚠ Skipping ardoq"
|
|
171
188
|
|
|
172
189
|
[ -n "$ANTHROPIC_AUTH_TOKEN" ] && [ -n "$LLM_GATEWAY_HOST" ] && \
|
|
173
190
|
upsert_secret "litellm" "$LLM_GATEWAY_HOST" "Authorization" "Bearer $ANTHROPIC_AUTH_TOKEN" || \
|
|
174
191
|
echo " ⚠ Skipping litellm"
|
|
175
192
|
|
|
193
|
+
[ -n "$XLEDGER_API_TOKEN" ] && [ -n "$XLEDGER_HOST" ] && \
|
|
194
|
+
upsert_secret "xledger" "$XLEDGER_HOST" "Authorization" "token $XLEDGER_API_TOKEN" || \
|
|
195
|
+
echo " ⚠ Skipping xledger"
|
|
196
|
+
|
|
176
197
|
echo ""
|
|
177
198
|
|
|
178
199
|
# ── Register global-claw agent if missing ────────────────────────────────────
|
|
@@ -219,7 +240,14 @@ if ! python3 -c "import yaml" 2>/dev/null; then
|
|
|
219
240
|
pip3 install pyyaml --quiet --break-system-packages 2>/dev/null || \
|
|
220
241
|
pip3 install pyyaml --quiet 2>/dev/null || \
|
|
221
242
|
pip install pyyaml --quiet 2>/dev/null || \
|
|
222
|
-
{ echo "
|
|
243
|
+
{ echo " ⚠ Could not install PyYAML — skipping agent secret linking. Run: pip3 install pyyaml"; SKIP_LINKING=1; }
|
|
244
|
+
fi
|
|
245
|
+
|
|
246
|
+
if [ "${SKIP_LINKING:-0}" = "1" ]; then
|
|
247
|
+
echo " ⚠ Skipping agent secret linking (PyYAML unavailable)"
|
|
248
|
+
echo ""
|
|
249
|
+
echo "Done."
|
|
250
|
+
exit 0
|
|
223
251
|
fi
|
|
224
252
|
|
|
225
253
|
echo "Linking secrets to agents (from agents.yaml)..."
|
package/template/src/index.ts
CHANGED
|
@@ -87,23 +87,21 @@ const queue = new GroupQueue();
|
|
|
87
87
|
|
|
88
88
|
const onecli = new OneCLI({ url: ONECLI_URL });
|
|
89
89
|
|
|
90
|
-
function ensureOneCLIAgent(jid: string, group: RegisteredGroup): void {
|
|
90
|
+
async function ensureOneCLIAgent(jid: string, group: RegisteredGroup): Promise<void> {
|
|
91
91
|
if (group.isMain) return;
|
|
92
92
|
const identifier = group.folder.toLowerCase().replace(/_/g, '-');
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
(err) => {
|
|
93
|
+
try {
|
|
94
|
+
const res = await onecli.ensureAgent({ name: group.name, identifier });
|
|
95
|
+
logger.info(
|
|
96
|
+
{ jid, identifier, created: res.created },
|
|
97
|
+
'OneCLI agent ensured',
|
|
98
|
+
);
|
|
99
|
+
} catch (err) {
|
|
101
100
|
logger.debug(
|
|
102
101
|
{ jid, identifier, err: String(err) },
|
|
103
102
|
'OneCLI agent ensure skipped',
|
|
104
103
|
);
|
|
105
|
-
|
|
106
|
-
);
|
|
104
|
+
}
|
|
107
105
|
}
|
|
108
106
|
|
|
109
107
|
function loadState(): void {
|
|
@@ -757,15 +755,19 @@ async function main(): Promise<void> {
|
|
|
757
755
|
// Auto-register any agents from agents.yaml whose channel env vars are set.
|
|
758
756
|
autoRegisterAgentsFromYaml();
|
|
759
757
|
|
|
758
|
+
// Ensure all registered agents exist in OneCLI's PostgreSQL FIRST — must complete
|
|
759
|
+
// before ensureOneCLISecrets() runs, otherwise the secrets script cannot link
|
|
760
|
+
// secrets to agents that don't exist in OneCLI yet (race condition for new agents).
|
|
761
|
+
await Promise.all(
|
|
762
|
+
Object.entries(registeredGroups).map(([jid, group]) =>
|
|
763
|
+
ensureOneCLIAgent(jid, group),
|
|
764
|
+
),
|
|
765
|
+
);
|
|
766
|
+
|
|
760
767
|
// Ensure OneCLI secrets are up to date (re-runs only when credentials change).
|
|
768
|
+
// Runs after ensureOneCLIAgent so agents are guaranteed to exist in OneCLI.
|
|
761
769
|
ensureOneCLISecrets();
|
|
762
770
|
|
|
763
|
-
// Ensure OneCLI agents exist for all registered groups.
|
|
764
|
-
// Recovers from missed creates (e.g. OneCLI was down at registration time).
|
|
765
|
-
for (const [jid, group] of Object.entries(registeredGroups)) {
|
|
766
|
-
ensureOneCLIAgent(jid, group);
|
|
767
|
-
}
|
|
768
|
-
|
|
769
771
|
restoreRemoteControl();
|
|
770
772
|
|
|
771
773
|
// Graceful shutdown handlers
|