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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-ironclaws",
3
- "version": "1.0.0",
3
+ "version": "1.0.3",
4
4
  "description": "Create an IronClaws AI agent platform in seconds",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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 syntax. Use when responding to Slack channels (folder starts with "slack_" or JID contains slack identifiers).
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 Message Formatting (mrkdwn)
6
+ # Slack Formatting — World-Class Messages
7
7
 
8
- When responding to Slack channels, use Slack's mrkdwn syntax instead of standard Markdown.
8
+ Every message you send goes to Slack. Slack does not render standard Markdown. Follow these rules exactly.
9
9
 
10
- ## Slack context
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
- All agents in this deployment communicate via Slack. These formatting rules always apply.
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
- ## Formatting reference
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
- ### Text styles
103
+ > Christian — fill in `[INSERT ACCOUNT]` and send the correction email below.
104
+ ```
17
105
 
18
- | Style | Syntax | Example |
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
- ### Links and mentions
108
+ ## Status summaries
27
109
 
28
110
  ```
29
- <https://example.com|Link text> # Named link
30
- <https://example.com> # Auto-linked URL
31
- <@U1234567890> # Mention user by ID
32
- <#C1234567890> # Mention channel by ID
33
- <!here> # @here
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
- ### Lists
118
+ ---
119
+
120
+ ## Email and document drafts
38
121
 
39
- Slack supports simple bullet lists but NOT numbered lists:
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
- First item
43
- Second item
44
- Third item
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
- Use `•` (bullet character) or `- ` or `* ` for bullets.
147
+ ---
148
+
149
+ ## Progress updates (mid-run)
48
150
 
49
- ### Block quotes
151
+ Use `send_message` for long-running tasks so people know you're working:
50
152
 
51
153
  ```
52
- > This is a block quote
53
- > It can span multiple lines
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
- ### Emoji
167
+ The December close report cannot be marked complete until the annual true-up is logged.
57
168
 
58
- Use standard emoji shortcodes: `:white_check_mark:`, `:x:`, `:rocket:`, `:tada:`
169
+ Reply with:
170
+ `annual true-up done 2025: <summary including adjustment amount>`
171
+ ```
172
+
173
+ ---
59
174
 
60
- ## What NOT to use
175
+ ## Confirmations and success
61
176
 
62
- - **NO** `##` headings (use `*Bold text*` for headers instead)
63
- - **NO** `**double asterisks**` for bold (use `*single asterisks*`)
64
- - **NO** `[text](url)` links (use `<url|text>` instead)
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
- ## Example message
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
- _March 21, 2026_
187
+ ---
75
188
 
76
- *Completed:* Fixed authentication bug in login flow
77
- • *In Progress:* Building new dashboard widgets
78
- • *Blocked:* Waiting on API access from DevOps
189
+ ## Lists
79
190
 
80
- > Next sync: Monday 10am
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
- ## Quick rules
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
- 1. Use `*bold*` not `**bold**`
88
- 2. Use `<url|text>` not `[text](url)`
89
- 3. Use `•` bullets, avoid numbered lists
90
- 4. Use `:emoji:` shortcodes
91
- 5. Quote blocks with `>`
92
- 6. Skip headings use bold text instead
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 -euo pipefail
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 "ERROR: Could not install PyYAML. Run: pip3 install pyyaml"; exit 1; }
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)..."
@@ -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
- onecli.ensureAgent({ name: group.name, identifier }).then(
94
- (res) => {
95
- logger.info(
96
- { jid, identifier, created: res.created },
97
- 'OneCLI agent ensured',
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