feat: add skills/ directory with preserved history + AGENTS.md#1385
feat: add skills/ directory with preserved history + AGENTS.md#1385
Conversation
SDK reference (Python, Rust), core patterns (REST API, background jobs, cron tasks, workflows, state management, real-time streaming, pub/sub, channels), advanced (multi-trigger, custom triggers, AI agents, testing), and operations (deployment, observability).
Add explicit boundary rules and a data-driven endpoint-map example so prompts about `{ path, id }` looped registerFunction calls are steered to the http-invoked-functions pattern.
Documents all Motia framework patterns that will be removed from iii-prefixed skills, including per-skill details and the iii-sdk equivalents for each Motia concept. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove 16 iii-prefixed skills that contained outdated Motia framework patterns not matching the actual iii documentation. These will be rebuilt from scratch using the iii docs HOWTOs as the source of truth. Removed skills: iii-rest-api, iii-cron-tasks, iii-background-jobs, iii-state-management, iii-realtime-streaming, iii-custom-triggers, iii-pubsub, iii-workflows, iii-multi-trigger, iii-deployment, iii-observability, iii-python-sdk, iii-rust-sdk, iii-ai-agents, iii-channels, iii-testing See MOTIA_REMOVAL_SUMMARY.md for details on what was removed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Per the Agent Skills standard, reference files belong in a references/ subdirectory. Moved reference.js for all 7 pattern skills and updated SKILL.md paths accordingly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Created SKILL.md files for effect-system, event-driven-cqrs, and low-code-automation which previously only had reference.js files. Follows the same structure as the other pattern skills. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Deleted all REFERENCE.md files from HOWTO skill references/ - Created reference.js files for all 12 HOWTO skills (except engine-config) following the same structure as existing pattern skills - Rewrote all 13 SKILL.md files to remove fenced code blocks and config sections, matching the agentic-backend/SKILL.md template - engine-config/SKILL.md references ../references/iii-config.yaml (root) - All other skills reference references/reference.js Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Created references/iii-config.yaml with the full annotated engine config reference covering all modules and adapters - Created .github/workflows/sync-config.yml to auto-sync the config from https://iii.dev/docs/how-to/configure-engine on merge to main and weekly on Mondays - engine-config/SKILL.md already points to ../references/iii-config.yaml Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Minimal skills for node-sdk, python-sdk, and rust-sdk that point to the official SDK API reference docs at iii.dev/docs/api-reference/. Each lists key exports and notes specific to that language. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Lists all 23 skills grouped by category: HOWTO skills (13), architecture pattern skills (7), and SDK reference skills (3). Also references the shared iii-config.yaml. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Describes a plan for automatically adding, removing, and updating skills when HOWTOs change in the iii docs. Recommends a GitHub Action with AI agent approach that fetches llms.txt, diffs against current skills, generates content, and opens PRs for review. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Moved all per-skill references/reference.js files into a single root
references/ directory, named by skill (e.g., references/http-endpoints.js).
Updated all SKILL.md reference links to ../references/{skill-name}.js.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace outdated iii-prefixed skill references with the current 23 skills grouped by category: HOWTO skills, architecture patterns, and SDK references. Update install examples and format section to reflect the root references/ directory structure. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Chore/skills alignment
Expanded descriptions for queue-processing, state-management, trigger-actions, trigger-conditions, state-reactions, and cron-scheduling to include more concrete actions and natural trigger terms as flagged by tessl skill review. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Added "Engine Configuration" sections to 9 skills that reference modules, adapters, or queue_configs, pointing to the shared references/iii-config.yaml for the full annotated config reference. Skills updated: cron-scheduling, queue-processing, state-management, state-reactions, realtime-streams, observability, dead-letter-queues, agentic-backend, workflow-orchestration Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add explicit iii-config references to relevant skills and improve some descriptions
chore: make compatible with skillkit; fix README commands
update config to better baseline/defaults
Replace init() with registerWorker()/register_worker() across all skills (node-sdk, python-sdk, rust-sdk, functions-and-triggers, observability) to match the actual SDK exports. Update Rust SDK skill to use the new RegisterFunction builder API and pin version to 0.10. Add Python and Rust reference implementations for functions-and-triggers. Closes #8 items 1-4 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…CLI timeout - Add channels skill with SKILL.md and reference implementations (JS, Python, Rust) for binary streaming between workers - Add request/response format auto-registration docs to functions-and-triggers (schemars in Rust, type hints in Python, manual in Node.js) - Add --timeout-ms CLI flag mentions to dead-letter-queues and trigger-actions - Note CLI trigger is now part of the engine binary (not a separate tool) Closes #8 item 5 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Document the external worker module system: iii.toml manifest, iii worker CLI commands (add, remove, list, info), workers section in config.yaml with marker-delimited config blocks, and binary resolution from iii_workers/. Closes #8 remaining item (worker module system) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Clarify channel consumer behavior in channels/SKILL.md - Standardize on `iii-config.yaml` in engine-config/SKILL.md - Document synchronous `trigger()` usage in python-sdk/SKILL.md - Handle empty streams gracefully in JS and Python channel references - Prevent deadlock by using non-blocking trigger in Rust channel reference - Use `.get()` to prevent KeyErrors in Python functions-and-triggers reference
Fixes from Anthony's feedback on PR #11: - Restore leading slashes on api_path (their standard) - Revert cron config field from 'cron' back to 'expression' - Restore "When to Use" / "Boundaries" sections in all SKILL.md files - Remove incorrect per-language matrix from README (features at parity) Rename all skill folders with iii- prefix for marketplace indexing: - All 24 skill directories renamed (e.g. channels/ -> iii-channels/) - SKILL.md name fields updated to match directory names - All cross-references updated in README.md, SKILLS.md, and SKILL.md files - Python/Rust reference files included with fixes applied
fix: address Anthony's review + rename skills with iii- prefix
- README install commands now point to iii-hq/iii (not iii-hq/skills) - Added Getting Started section to README - Added iii-channels entry to SKILLS.md
- realtime-streams.js: fix createStream to use positional args (SDK signature) - channels.rs: add missing TriggerAction import - observability.rs: clone order_id before async move (borrow checker)
Installation, first worker, and next steps — walks through engine install, project creation, SDK setup, shows first worker in TS/Python/Rust, and points to npx skills add iii-hq/iii for agent skills.
'state::set/get/update' reads as a literal function ID with slashes. Expanded to separate names so agents don't confuse shorthand with real function IDs. Fixes feedback from Mike and Anthony.
Commands first, three-tier boundaries (always/ask first/never), code style examples in Rust/TS/Python. Follows GitHub's 2,500-repo analysis best practices.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThis PR introduces comprehensive documentation for the iii engine framework, including repository operating procedures (AGENTS.md with setup, build, and deployment guidelines), a structured skills catalog system with 25+ skill guides (each documenting a specific pattern, use case, and boundary rules), and 100+ runnable reference implementations across JavaScript/TypeScript, Python, and Rust demonstrating practical application of each skill. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes The changes consist of homogeneous documentation and reference implementations following consistent patterns across 25+ skill guides and 100+ runnable examples. While large in scope, each file exhibits predictable structure (YAML frontmatter + markdown for skills; boilerplate worker/function registration for implementations), minimal logic density, and repetitive patterns across the three language SDKs. No complex architectural changes, API modifications, or intricate logic require deep analysis—primarily additive content demonstrating established framework patterns. Possibly related issues
Possibly related PRs
Suggested reviewers
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
Actionable comments posted: 13
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
🟡 Minor comments (12)
skills/references/custom-triggers.py-85-111 (1)
85-111:⚠️ Potential issue | 🟡 MinorHandle 304 Not Modified responses via
HTTPErrorexception.
urllib.request.urlopen()raisesurllib.error.HTTPErrorfor 304 responses instead of returning a response object. Theresp.status == 304check at line 92 is unreachable, causing 304 responses to be caught by the generic exception handler and logged as failures instead of being handled normally.Wrap the
urlopen()call in a try-except block and check the exception code:Suggested fix
async def _poll_loop(trigger_id, function_id, url, interval_ms): import urllib.request + import urllib.error import json last_etag = None interval_s = interval_ms / 1000 while True: try: req = urllib.request.Request(url, method="GET") if last_etag: req.add_header("If-None-Match", last_etag) - resp = await asyncio.to_thread(urllib.request.urlopen, req) - - if resp.status == 304: - await asyncio.sleep(interval_s) - continue + try: + resp = await asyncio.to_thread(urllib.request.urlopen, req) + except urllib.error.HTTPError as err: + if err.code == 304: + await asyncio.sleep(interval_s) + continue + raise etag = resp.headers.get("ETag")🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/references/custom-triggers.py` around lines 85 - 111, The polling loop currently expects resp.status == 304 but urllib.request.urlopen raises urllib.error.HTTPError for 304, so wrap the call to asyncio.to_thread(urllib.request.urlopen, req) in a try/except that catches urllib.error.HTTPError (importing urllib.error if needed), and if the caught exception has .code == 304 perform the same await asyncio.sleep(interval_s) and continue; for other HTTPError codes re-raise or log as before so they hit the existing generic exception handler. Update the logic around last_etag/etag handling in the try block (the resp.status check is unreachable) so successful responses continue to parse resp and call iii.trigger_async as before.skills/references/workflow-orchestration.js-219-223 (1)
219-223:⚠️ Potential issue | 🟡 MinorLet the generated
order_idwin in the enqueue payload.Line 221 spreads
dataafterorder_id, so a caller-supplieddata.order_idoverrides the ID you just persisted and return. That can make the queued workflow mutate a different record than the one created.🛠️ Suggested fix
- payload: { order_id, ...data, force_payment_failure, fail_until_payment_attempt }, + payload: { ...data, order_id, force_payment_failure, fail_until_payment_attempt },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/references/workflow-orchestration.js` around lines 219 - 223, The payload currently spreads data after order_id so a caller-provided data.order_id can override the persisted ID; update the enqueue payload in the iii.trigger call (function iii.trigger, variable enqueueResult) so the authoritative order_id wins — either spread data first and then set order_id last, or delete/order_id from data before spreading — ensuring the payload contains the generated order_id value passed to the queued workflow.skills/references/http-endpoints.js-92-100 (1)
92-100:⚠️ Potential issue | 🟡 MinorUpdate response omits the actual persisted shape.
Line 99 returns
{ id, ...updates }, but Line 92 also writesupdated_atand unchanged fields remain in state. Returning the stored object would keep the example behavior consistent for clients.💡 Proposed fix
await iii.trigger({ function_id: 'state::update', payload: { scope: 'users', key: id, ops }, }) - return { status_code: 200, body: { id, ...updates } } + const updated = await iii.trigger({ + function_id: 'state::get', + payload: { scope: 'users', key: id }, + }) + + return { status_code: 200, body: updated } })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/references/http-endpoints.js` around lines 92 - 100, The response currently returns { id, ...updates } which omits persisted fields (like updated_at) and unchanged data; after calling iii.trigger with function_id: 'state::update' (using ops, id, updates), fetch the stored record via iii.trigger with function_id: 'state::get' (scope: 'users', key: id) and return that full persisted object in the response body so clients receive the actual saved shape.skills/iii-observability/SKILL.md-44-49 (1)
44-49:⚠️ Potential issue | 🟡 MinorFix awkward sentence split in reference implementation section.
The sentence starting on line 44 is interrupted by the Python and Rust reference links (lines 46-48) and then completed on line 49, making it difficult to read. Restructure so the sentence completes before listing the alternative language implementations.
📝 Suggested restructure
-See [../references/observability.js](../references/observability.js) for the full working example — a worker with custom spans, - -Also available in **Python**: [../references/observability.py](../references/observability.py) - -Also available in **Rust**: [../references/observability.rs](../references/observability.rs) -metrics counters, trace propagation, and log subscriptions connected to an OTel collector. +See [../references/observability.js](../references/observability.js) for the full working example — a worker with custom spans, metrics counters, trace propagation, and log subscriptions connected to an OTel collector. + +Also available in **Python**: [../references/observability.py](../references/observability.py) + +Also available in **Rust**: [../references/observability.rs](../references/observability.rs)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/iii-observability/SKILL.md` around lines 44 - 49, The README text in SKILL.md splits one sentence across the JS reference and the Python/Rust links causing awkward flow; update the paragraph so the complete sentence describing the example ("a worker with custom spans, metrics counters, trace propagation, and log subscriptions connected to an OTel collector") follows the JS reference link (../references/observability.js) and then list the alternate implementations ("Also available in Python: ../references/observability.py" and "Also available in Rust: ../references/observability.rs") on their own lines, ensuring the description is one coherent sentence before the language links.skills/iii-dead-letter-queues/SKILL.md-40-45 (1)
40-45:⚠️ Potential issue | 🟡 MinorFix awkward sentence split in reference implementation section.
Similar to the observability skill, the sentence starting on line 40 is interrupted by the Python and Rust reference links and completed on line 45, disrupting readability.
📝 Suggested restructure
-See [../references/dead-letter-queues.js](../references/dead-letter-queues.js) for the full working example — inspecting DLQ status, - -Also available in **Python**: [../references/dead-letter-queues.py](../references/dead-letter-queues.py) - -Also available in **Rust**: [../references/dead-letter-queues.rs](../references/dead-letter-queues.rs) -redriving failed jobs via SDK and CLI, and configuring retry behavior. +See [../references/dead-letter-queues.js](../references/dead-letter-queues.js) for the full working example — inspecting DLQ status, redriving failed jobs via SDK and CLI, and configuring retry behavior. + +Also available in **Python**: [../references/dead-letter-queues.py](../references/dead-letter-queues.py) + +Also available in **Rust**: [../references/dead-letter-queues.rs](../references/dead-letter-queues.rs)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/iii-dead-letter-queues/SKILL.md` around lines 40 - 45, The sentence in SKILL.md is split by the Python and Rust links, breaking readability; rephrase so the main sentence about the full working example in ../references/dead-letter-queues.js is continuous and then list language-specific links after it. Concretely, combine the clause "redriving failed jobs via SDK and CLI, and configuring retry behavior" with the earlier "inspecting DLQ status" phrase in the ../references/dead-letter-queues.js sentence (the line referencing references/dead-letter-queues.js) and then put "Also available in Python: ../references/dead-letter-queues.py" and "Also available in Rust: ../references/dead-letter-queues.rs" as separate trailing sentences or items.skills/references/trigger-conditions.rs-220-223 (1)
220-223:⚠️ Potential issue | 🟡 MinorUpdate to use
shutdown_async().awaitfor proper telemetry flush.
shutdown()is deprecated in the Rust SDK. Useshutdown_async().awaitinstead to guarantee telemetry is flushed before process exit. Move it inside the async block where it can be awaited:Change
- tokio::runtime::Runtime::new().unwrap().block_on(async { - tokio::signal::ctrl_c().await.ok(); - }); - iii.shutdown(); + tokio::runtime::Runtime::new().unwrap().block_on(async { + tokio::signal::ctrl_c().await.ok(); + iii.shutdown_async().await; + });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/references/trigger-conditions.rs` around lines 220 - 223, The shutdown call currently uses iii.shutdown() after blocking on an async block, which is deprecated and can drop telemetry; move the shutdown into the async context and await the async variant: inside the tokio::runtime::Runtime::new().unwrap().block_on(async { ... }) block, after awaiting tokio::signal::ctrl_c().await.ok(), call and await iii.shutdown_async().await instead of calling iii.shutdown() outside the async block so telemetry is flushed before exit.skills/references/http-endpoints.rs-34-52 (1)
34-52:⚠️ Potential issue | 🟡 MinorVariable
idused after move injson!macro.The
idvariable is moved into thejson!macro at line 45, then used again at line 52 inlogger.info. SinceStringdoesn't implementCopy, this would cause a compile error.🔧 Proposed fix: Clone `id` before use in json! macro
- let id = format!("usr-{:x}", std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_nanos()); + let id = format!("usr-{:x}", std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_nanos()); + let id_clone = id.clone(); let user = json!({ - "id": id, + "id": id_clone, "name": req.body.name, "email": req.body.email, "created_at": chrono::Utc::now().to_rfc3339(), });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/references/http-endpoints.rs` around lines 34 - 52, The variable id is being moved into the json! macro when building user and then reused in logger.info, causing a move error; fix by ensuring id is cloned when inserted into the json! payload (or otherwise use a borrowed &id) so the original String remains available for subsequent use by logger.info and in the TriggerRequest payload (look for the id variable, the json! call that constructs user, the TriggerRequest instantiation, and the logger.info call).skills/iii-getting-started/SKILL.md-141-147 (1)
141-147:⚠️ Potential issue | 🟡 MinorUpdate the skills count to 25.
Line 143 still says 24 skills, but this PR’s own discovery target is 25
iii-*skills, so the copy is already stale.💡 Suggested fix
-Get all 24 iii skills for your AI coding agent: +Get all 25 iii skills for your AI coding agent:🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/iii-getting-started/SKILL.md` around lines 141 - 147, Update the text under the "Install Agent Skills" section: change the phrase "Get all 24 iii skills for your AI coding agent:" to "Get all 25 iii skills for your AI coding agent:" so the count matches the repository's current discovery target; this is the copy near the "Install Agent Skills" heading and the `npx skills add iii-hq/iii` example.skills/references/channels.rs-138-140 (1)
138-140:⚠️ Potential issue | 🟡 MinorUse
tokio::signal::ctrl_c()and update to the non-deprecatedshutdown_async()API.The infinite sleep on line 139 prevents graceful shutdown, and
shutdown()is deprecated in the iii Rust SDK. Align with the pattern used in other reference files and production code by listening for a shutdown signal and calling the async shutdown method.Suggested fix
- tokio::time::sleep(Duration::from_secs(u64::MAX)).await; - iii.shutdown(); + tokio::signal::ctrl_c().await.ok(); + iii.shutdown_async().await;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/references/channels.rs` around lines 138 - 140, Replace the infinite sleep and deprecated synchronous shutdown with a Ctrl-C signal handler and the async shutdown API: remove tokio::time::sleep(Duration::from_secs(u64::MAX)).await and instead await tokio::signal::ctrl_c(), then call iii.shutdown_async().await (or the async method name provided by the iii SDK) to perform graceful shutdown; ensure any errors from shutdown_async() are handled or logged.skills/references/cron-scheduling.rs-255-258 (1)
255-258:⚠️ Potential issue | 🟡 MinorUse
shutdown_async().awaitin the Rust exit path.Line 258 calls the deprecated
shutdown()method. Since lines 255–257 already hold a Tokio runtime for Ctrl-C handling, callshutdown_async().awaitwithin that async block to ensure telemetry is flushed before process exit.Suggested fix
- tokio::runtime::Runtime::new().unwrap().block_on(async { - tokio::signal::ctrl_c().await.ok(); - }); - iii.shutdown(); + tokio::runtime::Runtime::new().unwrap().block_on(async move { + tokio::signal::ctrl_c().await.ok(); + iii.shutdown_async().await; + });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/references/cron-scheduling.rs` around lines 255 - 258, The exit path currently creates a Tokio runtime to await Ctrl-C then calls the deprecated synchronous iii.shutdown(); move the shutdown to the async context and call the async flush method by invoking iii.shutdown_async().await inside the same tokio::runtime::Runtime::new().unwrap().block_on(async { ... }) block (after tokio::signal::ctrl_c().await.ok()) so telemetry is flushed before process exit; replace the iii.shutdown() call with that async call and remove the synchronous shutdown usage.skills/references/state-reactions.rs-108-109 (1)
108-109:⚠️ Potential issue | 🟡 MinorType error:
and_thenclosure doesn't returnOptionThis line will not compile.
v["customer"].clone()returnsserde_json::Value, and calling.into()on it doesn't convert toOption<_>. Theand_thencombinator expects the closure to returnOption<T>.🐛 Proposed fix
- let customer = event.new_value.as_ref().and_then(|v| v["customer"].clone().into()); + let customer = event.new_value.as_ref().and_then(|v| v.get("customer").cloned());🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/references/state-reactions.rs` around lines 108 - 109, The second line uses and_then but the closure returns a serde_json::Value (via v["customer"].clone().into()) instead of an Option, causing a type error; change the combinator to map or use v.get("customer").cloned() (which returns Option<Value>) and then convert that Value to the desired Rust type (e.g., use as_str().map(|s| s.to_string()) or as_i64()/as_f64() as appropriate) so that customer is an Option of the correct type; update the expression that assigns customer (which reads event.new_value) accordingly.skills/references/http-invoked-functions.js-189-193 (1)
189-193:⚠️ Potential issue | 🟡 MinorFix cron expression format inconsistency across reference files.
The codebase mixes two cron expression formats:
- 7-field (used in
http-invoked-functions.js):'0 0 * * * * *'(second, minute, hour, day, month, weekday, year)- 5-field (used in
dead-letter-queues.js):'0 * * * *'(minute, hour, day, month, weekday)The
cron-scheduling.pydocumentation explicitly defines the iii engine as using 7-field cron expressions. Align all reference files to use the 7-field format consistently, includingdead-letter-queues.jsanddead-letter-queues.py.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/references/http-invoked-functions.js` around lines 189 - 193, The project mixes 5-field and 7-field cron formats; update any iii.registerTrigger cron expressions (e.g., the config.expression used with type: 'cron' and function_id like 'integrations::hourly-heartbeat') to the engine's 7-field format (second minute hour day month weekday year). For each 5-field string (minute hour day month weekday) in dead-letter-queues.js and dead-letter-queues.py, convert it by prefixing a "0" for seconds and appending " *" for the year (e.g., "0 * * * *" -> "0 0 * * * * *") so all references use the 7-field format consistently.
🧹 Nitpick comments (15)
skills/references/realtime-streams.rs (1)
364-367: Prefershutdown_async().awaitin the Rust reference example.The current example uses the deprecated synchronous API. Moving
shutdown_async()into the existing Tokio block keeps the reference aligned with the SDK's recommended pattern and guarantees telemetry flush before process exit.🛠️ Suggested update
- tokio::runtime::Runtime::new().unwrap().block_on(async { - tokio::signal::ctrl_c().await.ok(); - }); - iii.shutdown(); + let iii = iii.clone(); + tokio::runtime::Runtime::new().unwrap().block_on(async move { + tokio::signal::ctrl_c().await.ok(); + iii.shutdown_async().await; + });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/references/realtime-streams.rs` around lines 364 - 367, Replace the synchronous shutdown call with the async shutdown helper: inside the existing Tokio block (the tokio::runtime::Runtime::new().unwrap().block_on(async { ... })), await the SDK's async shutdown method instead of calling iii.shutdown(); specifically call iii.shutdown_async().await from within that async block so the shutdown runs on the runtime and guarantees telemetry flush before exit.skills/iii-trigger-actions/SKILL.md (1)
39-44: Reference paragraph is hard to parse.Like the other skill docs, this reads better as a compact list (
JS,Python,Rust) instead of one sentence interrupted by language links.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/iii-trigger-actions/SKILL.md` around lines 39 - 44, Replace the one-line reference paragraph with a compact list of language-specific links to improve readability: convert the sentence that mixes links into three short items (JS: ../references/trigger-actions.js, Python: ../references/trigger-actions.py, Rust: ../references/trigger-actions.rs) and append a brief clarifying phrase like "invocation modes showing sync, void, and enqueue patterns" so the SKILL.md paragraph reads as a concise list referencing those files.skills/iii-trigger-conditions/SKILL.md (1)
39-45: Reference section reads as a broken sentence.The sentence started on Line 39 is interrupted by the “Also available…” lines and resumes on Line 44. Consider converting these into a short bullet list for cleaner scanability.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/iii-trigger-conditions/SKILL.md` around lines 39 - 45, The reference paragraph in SKILL.md is broken by inline “Also available…” lines; change it to one clear sentence describing the example (e.g., "See ../references/trigger-conditions.js for the full working example where a business rule function filters events before the handler processes them.") followed by a short bullet list of language variants referencing trigger-conditions.js, trigger-conditions.py, and trigger-conditions.rs; ensure the clause "where a business rule function filters events before the handler processes them" remains attached to the main sentence rather than split across the list.AGENTS.md (1)
39-50: Specify language for fenced code block.The project map code block should have a language identifier for clarity and to satisfy markdown linters. Use
textorplaintextfor non-code content.📝 Proposed fix
## Project Map -``` +```text engine/ Rust engine — runtime, modules, protocol, CLI sdk/packages/node/iii/ TypeScript SDK (npm: iii-sdk) sdk/packages/python/iii/ Python SDK (PyPI: iii-sdk)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@AGENTS.md` around lines 39 - 50, Add a language identifier to the fenced code block in the AGENTS.md snippet so markdown linters and renderers treat it as plain text; change the opening ``` to ```text (or ```plaintext) for the project map block so the block contains ` ```text` followed by the same lines shown in the diff and the closing ``` remains unchanged.skills/references/observability.rs (1)
272-278: Use the async shutdown API in the cleanup path.This section explicitly teaches clean teardown. Ending with deprecated
iii.shutdown()points readers at the obsolete lifecycle API.Suggested edit
tokio::runtime::Runtime::new().unwrap().block_on(async { tokio::signal::ctrl_c().await.ok(); #[cfg(feature = "otel")] shutdown_otel().await; - }); - iii.shutdown(); + + iii.shutdown_async().await; + });The Rust SDK has deprecated
shutdown()in favor ofshutdown_async().awaitto guarantee telemetry flush before the process exits. Since this example covers observability specifically, showing the correct shutdown pattern is important.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/references/observability.rs` around lines 272 - 278, The code currently calls the deprecated synchronous API iii.shutdown() after the tokio::runtime::Runtime::new().unwrap().block_on(...) block; replace this with the async shutdown API by moving the SDK shutdown into the async block and calling iii.shutdown_async().await (alongside the existing #[cfg(feature = "otel")] shutdown_otel().await) so the shutdown is awaited and telemetry is flushed before exit; remove the deprecated iii.shutdown() call and ensure the call site is inside the block_on async context where tokio::signal::ctrl_c().await is handled.skills/references/state-management.rs (1)
7-10: Unused import:TriggerAction.
TriggerActionis imported but never used in this file. All trigger calls useaction: None.🧹 Remove unused import
use iii_sdk::{ - register_worker, InitOptions, RegisterFunction, TriggerRequest, TriggerAction, + register_worker, InitOptions, RegisterFunction, TriggerRequest, builtin_triggers::*, IIITrigger, Logger, };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/references/state-management.rs` around lines 7 - 10, Remove the unused import TriggerAction from the use list in this module; locate the import statement that declares TriggerAction alongside register_worker, InitOptions, RegisterFunction, TriggerRequest, builtin_triggers::*, IIITrigger, and Logger and delete TriggerAction since all trigger calls use action: None and the symbol is never referenced (ensure no other code in this file relies on TriggerAction before removing).skills/iii-agentic-backend/SKILL.md (1)
41-41: Consider consistent backtick formatting for primitives.The table cell
trigger \state::set`, `state::get`, `state::update`` doesn't wrap "trigger" in backticks, while line 58 has the same inconsistency. For consistency with other primitive references in the table, consider:📝 Suggested formatting fix
-| trigger `state::set`, `state::get`, `state::update` | Shared context between agents | +| `trigger` `state::set`, `state::get`, `state::update` | Shared context between agents |🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/iii-agentic-backend/SKILL.md` at line 41, Wrap the word "trigger" in backticks to match the existing primitive formatting for the entries that reference state operations: change the table cell that currently reads trigger `state::set`, `state::get`, `state::update` to use backticks around "trigger" (i.e., `trigger` `state::set`, `state::get`, `state::update`), and make the same change for the similar inconsistent occurrence later (the other table cell on line ~58) so all primitive references are consistently backticked.skills/references/dead-letter-queues.rs (1)
230-233: Add an optional inline comment about the deprecated shutdown pattern instead of requiring code changes.Line 233 uses the deprecated
shutdown()method; for educational clarity, consider adding a comment thatshutdown_async().awaitis preferred in production code but omitted here for reference simplicity.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/references/dead-letter-queues.rs` around lines 230 - 233, The call to iii.shutdown() uses the deprecated synchronous shutdown pattern; instead of changing behavior, add a brief inline comment next to the iii.shutdown() invocation explaining that this synchronous shutdown is used here for brevity and that production code should call the async variant (e.g., shutdown_async().await) after awaiting tokio::signal::ctrl_c() — reference the iii.shutdown() call and the preferred shutdown_async().await method so readers know the recommended replacement.skills/references/http-endpoints.py (1)
18-18: Unused import:TriggerAction
TriggerActionis imported but not used in this file. Consider removing it to keep the example focused.🔧 Suggested fix
-from iii import InitOptions, Logger, TriggerAction, register_worker +from iii import InitOptions, Logger, register_worker🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/references/http-endpoints.py` at line 18, The import list in this module includes an unused symbol TriggerAction; remove TriggerAction from the import statement (leaving InitOptions, Logger, register_worker) to eliminate the unused import and keep the example focused—update the import line that currently names TriggerAction so it no longer references that symbol.skills/references/queue-processing.rs (1)
23-23: Unused import:Duration
std::time::Durationis imported but not used in this file.🔧 Suggested fix
-use std::time::Duration;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/references/queue-processing.rs` at line 23, The import std::time::Duration in skills/references/queue-processing.rs is unused; either remove the unused use std::time::Duration; line or actually use Duration where intended (for example in functions like process_queue or backoff logic) — locate the use statement and delete it if no timing functionality is needed, or replace/add references to Duration in the relevant function (e.g., process_queue, handle_item, or retry/backoff helpers) so the import is utilized.skills/references/state-management.js (1)
12-12: Unused import:TriggerAction
TriggerActionis imported but not used in this file. Consider removing it.🔧 Suggested fix
-import { registerWorker, Logger, TriggerAction } from 'iii-sdk' +import { registerWorker, Logger } from 'iii-sdk'🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/references/state-management.js` at line 12, The import list in skills/references/state-management.js includes an unused symbol TriggerAction; remove TriggerAction from the import statement (leaving registerWorker and Logger) to eliminate the unused import and any linter warnings, i.e., update the import line that currently references TriggerAction so it only imports the actually used identifiers.skills/references/http-invoked-functions.rs (1)
20-20: Unused import:Duration
std::time::Durationis imported but not used in this file.🔧 Suggested fix
-use std::time::Duration;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/references/http-invoked-functions.rs` at line 20, The file currently imports std::time::Duration but never uses it; remove the unused import statement to eliminate the warning. Locate the top-level use declaration referencing Duration in http-invoked-functions.rs and delete the "use std::time::Duration;" line (or if you actually intended to use Duration, add the proper usage where needed in the function that requires timing). Ensure no other references to Duration remain so the file compiles cleanly.skills/references/state-reactions.rs (1)
13-13: Unused import:Duration
std::time::Durationis imported but not used in this file.🔧 Suggested fix
-use std::time::Duration;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/references/state-reactions.rs` at line 13, Remove the unused import of std::time::Duration (the Duration symbol) from the top of the file (the use std::time::Duration; line) or, if you intended to use it, actually reference Duration in the relevant code path; otherwise simply delete the import to resolve the unused-import warning.skills/references/observability.py (1)
154-156: Consider usingasyncio.new_event_loop()for Python 3.10+ compatibility.
asyncio.get_event_loop()is deprecated when called without a running event loop (Python 3.10+). In a signal handler context, this may raise warnings or fail. A safer pattern:♻️ Suggested fix
def _shutdown(signum, frame): - asyncio.get_event_loop().run_until_complete(iii.shutdown_otel()) + loop = asyncio.new_event_loop() + loop.run_until_complete(iii.shutdown_otel()) + loop.close() raise SystemExit(0)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/references/observability.py` around lines 154 - 156, The signal handler _shutdown currently calls asyncio.get_event_loop(), which is deprecated without a running loop; change it to create a fresh event loop, set it as current, run the coroutine iii.shutdown_otel() on it, then close the loop: create a new loop via asyncio.new_event_loop(), call asyncio.set_event_loop(loop) (or temporarily use loop.run_until_complete without setting if you prefer), await/ run_until_complete iii.shutdown_otel(), then loop.close() and finally raise SystemExit(0); this ensures compatibility on Python 3.10+ and that iii.shutdown_otel() (a coroutine) runs on a proper event loop.skills/references/cron-scheduling.py (1)
61-65: 7-field cron expressions used consistently here — but inconsistent with JS references.This file correctly uses 7-field cron expressions throughout (
second minute hour day month weekday year). However,dead-letter-queues.jsuses 5-field expressions. Consider aligning all reference files to the same format for consistency.Per the file's docstring (lines 5-6), the 7-field format is documented, so this file is internally consistent.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/references/cron-scheduling.py` around lines 61 - 65, This cron trigger uses a 7-field cron expression via iii.register_trigger (function_id "cron::hourly-cleanup") but other references (notably dead-letter-queues.js) use 5-field expressions; align formats across the repo by updating the 5-field expressions in dead-letter-queues.js to the documented 7-field format (second minute hour day month weekday year) so all cron expressions follow the docstring convention — locate cron expressions in dead-letter-queues.js and expand them to include seconds (and year if used elsewhere) matching the pattern used by iii.register_trigger.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@skills/iii-custom-triggers/SKILL.md`:
- Around line 19-20: The SKILL.md uses the deprecated positional call
iii.trigger(function_id, event); update every usage (lines referencing
iii.trigger) to the structured request form iii.trigger({ function_id, payload
}) so the SDK accepts the call; search for all occurrences of iii.trigger and
replace the positional signature with the object form using keys function_id and
payload, and verify any examples/reference text mention the request-object shape
rather than the old positional parameters; keep mention of unregisterTriggerType
as-is.
In `@skills/iii-effect-system/SKILL.md`:
- Around line 3-6: The activation description in SKILL.md currently mentions
"retry", which biases selection for retry/DLQ scenarios; remove the word "retry"
from the description paragraph (the description: "Builds composable, pipeable
function chains... retry.") and replace or rephrase to clarify synchronous
trigger chaining (e.g., mention failures stop the pipeline) and, if needed, add
a note directing retry-heavy flows to use TriggerAction.Enqueue({ queue }) or
the iii-workflow-orchestration skill instead; update the description string in
SKILL.md accordingly.
In `@skills/iii-getting-started/SKILL.md`:
- Around line 47-50: Replace the npm install instruction in the code block in
SKILL.md (the TypeScript / Node.js example) with the pnpm equivalent: change the
command that installs iii-sdk to use pnpm install and update any surrounding
text if it references npm; ensure the example follows repo guideline "Use pnpm
(never npm) for JS/TS" so the TypeScript/Node.js install step consistently uses
pnpm across the getting-started skill.
In `@skills/iii-node-sdk/SKILL.md`:
- Around line 16-18: The Install snippet in SKILL.md currently uses "npm install
iii-sdk"; update the documentation to follow repo convention by replacing that
command with the pnpm equivalent ("pnpm add iii-sdk") in the Install section and
any other occurrences; ensure the Install code block under the "## Install"
heading and any related examples use pnpm (not npm) to comply with the "Use pnpm
(never npm) for JS/TS" guideline.
- Around line 20-35: Rename the section title from "Key Exports" to "Key APIs"
and update the table to reflect which functions are top-level vs instance
methods: keep registerWorker(...) as a top-level export but prefix the instance
SDK methods with "iii." — specifically change registerFunction({ id }, handler)
to iii.registerFunction(...), registerTrigger({ type, function_id, config }) to
iii.registerTrigger(...), createStream(name, adapter) to iii.createStream(...),
and registerTriggerType(id, handler) to iii.registerTriggerType(...); leave
other symbols (trigger, TriggerAction.Void/Enqueue, Logger, withSpan, getTracer,
getMeter, createChannel) as-is but verify their ownership is correct in the
table.
In `@skills/references/channels.js`:
- Around line 58-84: The consumer registered in pipeline::consume incorrectly
uses the raw serializable ref (data.readerRef) instead of constructing a
ChannelReader; change the assignment for reader to instantiate the SDK reader
(e.g. new ChannelReader(iii.address, data.readerRef)) so subsequent calls to
reader.onMessage and reader.readAll work; keep the Logger usage and rest of the
processing logic the same but replace the direct ref usage with the
ChannelReader constructor to properly reconstruct the reader.
In `@skills/references/dead-letter-queues.py`:
- Around line 180-184: The cron expression passed to iii.register_trigger for
function_id "admin::auto-redrive" uses a 5-field format ("0 * * * *") but the
engine requires a 7-field expression under the config key "expression". Update
the config.expression to a 7-field cron string (sec min hour dom month dow year)
that matches the original intent (e.g., run at second 0, minute 0 of every hour)
so the trigger registration in iii.register_trigger uses the correct 7-field
format.
In `@skills/references/functions-and-triggers.rs`:
- Around line 167-203: The code currently moves input.order_id and input.items
into the first json! call, causing later uses to fail; fix by extracting owned
copies or references before the first trigger (e.g., let order_id =
input.order_id.clone(); let items = input.items.clone(); or
&input.order_id/&input.items if lifetimes allow) and then use those variables in
all TriggerRequest payloads (used with iii.trigger and TriggerRequest for
"orders::validate", "notifications::on-order-complete", and "orders::fulfill")
so no field is moved more than once.
In `@skills/references/http-invoked-functions.py`:
- Around line 158-162: The state trigger registered via iii.register_trigger for
"integrations::order-webhook" is filtering on the wrong key ("status") so it
never matches the state writes that use data["orderId"]; update the trigger's
config to use the same key used when writing state (i.e., the orderId key)
instead of "status" — replace "key": "status" with the same
expression/identifier used at the state write sites (data["orderId"] or its
evaluated value) so register_trigger(...) will match the state updates sent to
integrations::order-webhook.
In `@skills/references/queue-processing.js`:
- Around line 85-90: The example fires a notification to function_id
'notifications::send' but that function isn't registered in this standalone
reference, breaking end-to-end execution; fix by registering a local handler
named 'notifications::send' (or replace the trigger target with an inline/no-op
handler) in this file so the iii.trigger call has a reachable function: add a
registration using the same runtime API used elsewhere in the file (e.g.,
iii.registerFunction or iii.handle) with an async handler that accepts the
payload ({ type, orderId, chargeId }) and performs the illustrative action
(log/send) and ensure the handler's signature and behavior match the
fire-and-forget TriggerAction.Void() usage.
In `@skills/references/trigger-conditions.js`:
- Around line 140-146: The cron expression in the iii.registerTrigger call for
function_id 'reports::weekday-digest' uses a 5-field format ("0 8 * * *");
update the config.expression to the required 7-field format "0 0 8 * * * *" (sec
min hour dom month dow year) so the trigger conforms to the iii-cron-scheduling
skill; keep the rest of the registerTrigger block (type, function_id,
condition_function_id) unchanged.
- Around line 27-35: The condition and handler are using the wrong payload field
(data.value) — state-trigger events use { new_value, old_value, key, event_type
} — so update the functions registered as 'conditions::is-high-value' and
'orders::flag-high-value' to read totals from data.new_value (not data.value)
and use optional chaining (e.g., data.new_value?.total) to avoid crashes when
new_value is missing; ensure the logger uses data.key and data.new_value?.total
for safe logging.
In `@skills/references/trigger-conditions.rs`:
- Around line 211-215: The cron expression passed to CronTriggerConfig::new in
the iii.register_trigger call uses a 5-field format ("0 8 * * *"); update it to
the engine's 7-field format (second minute hour day month weekday year) used by
CronTriggerConfig, e.g. change the string to include seconds and year
placeholders like "0 0 8 * * * *" in the IIITrigger::Cron /
CronTriggerConfig::new invocation where .condition("conditions::is-weekday") is
set.
---
Minor comments:
In `@skills/iii-dead-letter-queues/SKILL.md`:
- Around line 40-45: The sentence in SKILL.md is split by the Python and Rust
links, breaking readability; rephrase so the main sentence about the full
working example in ../references/dead-letter-queues.js is continuous and then
list language-specific links after it. Concretely, combine the clause "redriving
failed jobs via SDK and CLI, and configuring retry behavior" with the earlier
"inspecting DLQ status" phrase in the ../references/dead-letter-queues.js
sentence (the line referencing references/dead-letter-queues.js) and then put
"Also available in Python: ../references/dead-letter-queues.py" and "Also
available in Rust: ../references/dead-letter-queues.rs" as separate trailing
sentences or items.
In `@skills/iii-getting-started/SKILL.md`:
- Around line 141-147: Update the text under the "Install Agent Skills" section:
change the phrase "Get all 24 iii skills for your AI coding agent:" to "Get all
25 iii skills for your AI coding agent:" so the count matches the repository's
current discovery target; this is the copy near the "Install Agent Skills"
heading and the `npx skills add iii-hq/iii` example.
In `@skills/iii-observability/SKILL.md`:
- Around line 44-49: The README text in SKILL.md splits one sentence across the
JS reference and the Python/Rust links causing awkward flow; update the
paragraph so the complete sentence describing the example ("a worker with custom
spans, metrics counters, trace propagation, and log subscriptions connected to
an OTel collector") follows the JS reference link
(../references/observability.js) and then list the alternate implementations
("Also available in Python: ../references/observability.py" and "Also available
in Rust: ../references/observability.rs") on their own lines, ensuring the
description is one coherent sentence before the language links.
In `@skills/references/channels.rs`:
- Around line 138-140: Replace the infinite sleep and deprecated synchronous
shutdown with a Ctrl-C signal handler and the async shutdown API: remove
tokio::time::sleep(Duration::from_secs(u64::MAX)).await and instead await
tokio::signal::ctrl_c(), then call iii.shutdown_async().await (or the async
method name provided by the iii SDK) to perform graceful shutdown; ensure any
errors from shutdown_async() are handled or logged.
In `@skills/references/cron-scheduling.rs`:
- Around line 255-258: The exit path currently creates a Tokio runtime to await
Ctrl-C then calls the deprecated synchronous iii.shutdown(); move the shutdown
to the async context and call the async flush method by invoking
iii.shutdown_async().await inside the same
tokio::runtime::Runtime::new().unwrap().block_on(async { ... }) block (after
tokio::signal::ctrl_c().await.ok()) so telemetry is flushed before process exit;
replace the iii.shutdown() call with that async call and remove the synchronous
shutdown usage.
In `@skills/references/custom-triggers.py`:
- Around line 85-111: The polling loop currently expects resp.status == 304 but
urllib.request.urlopen raises urllib.error.HTTPError for 304, so wrap the call
to asyncio.to_thread(urllib.request.urlopen, req) in a try/except that catches
urllib.error.HTTPError (importing urllib.error if needed), and if the caught
exception has .code == 304 perform the same await asyncio.sleep(interval_s) and
continue; for other HTTPError codes re-raise or log as before so they hit the
existing generic exception handler. Update the logic around last_etag/etag
handling in the try block (the resp.status check is unreachable) so successful
responses continue to parse resp and call iii.trigger_async as before.
In `@skills/references/http-endpoints.js`:
- Around line 92-100: The response currently returns { id, ...updates } which
omits persisted fields (like updated_at) and unchanged data; after calling
iii.trigger with function_id: 'state::update' (using ops, id, updates), fetch
the stored record via iii.trigger with function_id: 'state::get' (scope:
'users', key: id) and return that full persisted object in the response body so
clients receive the actual saved shape.
In `@skills/references/http-endpoints.rs`:
- Around line 34-52: The variable id is being moved into the json! macro when
building user and then reused in logger.info, causing a move error; fix by
ensuring id is cloned when inserted into the json! payload (or otherwise use a
borrowed &id) so the original String remains available for subsequent use by
logger.info and in the TriggerRequest payload (look for the id variable, the
json! call that constructs user, the TriggerRequest instantiation, and the
logger.info call).
In `@skills/references/http-invoked-functions.js`:
- Around line 189-193: The project mixes 5-field and 7-field cron formats;
update any iii.registerTrigger cron expressions (e.g., the config.expression
used with type: 'cron' and function_id like 'integrations::hourly-heartbeat') to
the engine's 7-field format (second minute hour day month weekday year). For
each 5-field string (minute hour day month weekday) in dead-letter-queues.js and
dead-letter-queues.py, convert it by prefixing a "0" for seconds and appending "
*" for the year (e.g., "0 * * * *" -> "0 0 * * * * *") so all references use the
7-field format consistently.
In `@skills/references/state-reactions.rs`:
- Around line 108-109: The second line uses and_then but the closure returns a
serde_json::Value (via v["customer"].clone().into()) instead of an Option,
causing a type error; change the combinator to map or use
v.get("customer").cloned() (which returns Option<Value>) and then convert that
Value to the desired Rust type (e.g., use as_str().map(|s| s.to_string()) or
as_i64()/as_f64() as appropriate) so that customer is an Option of the correct
type; update the expression that assigns customer (which reads event.new_value)
accordingly.
In `@skills/references/trigger-conditions.rs`:
- Around line 220-223: The shutdown call currently uses iii.shutdown() after
blocking on an async block, which is deprecated and can drop telemetry; move the
shutdown into the async context and await the async variant: inside the
tokio::runtime::Runtime::new().unwrap().block_on(async { ... }) block, after
awaiting tokio::signal::ctrl_c().await.ok(), call and await
iii.shutdown_async().await instead of calling iii.shutdown() outside the async
block so telemetry is flushed before exit.
In `@skills/references/workflow-orchestration.js`:
- Around line 219-223: The payload currently spreads data after order_id so a
caller-provided data.order_id can override the persisted ID; update the enqueue
payload in the iii.trigger call (function iii.trigger, variable enqueueResult)
so the authoritative order_id wins — either spread data first and then set
order_id last, or delete/order_id from data before spreading — ensuring the
payload contains the generated order_id value passed to the queued workflow.
---
Nitpick comments:
In `@AGENTS.md`:
- Around line 39-50: Add a language identifier to the fenced code block in the
AGENTS.md snippet so markdown linters and renderers treat it as plain text;
change the opening ``` to ```text (or ```plaintext) for the project map block so
the block contains ` ```text` followed by the same lines shown in the diff and
the closing ``` remains unchanged.
In `@skills/iii-agentic-backend/SKILL.md`:
- Line 41: Wrap the word "trigger" in backticks to match the existing primitive
formatting for the entries that reference state operations: change the table
cell that currently reads trigger `state::set`, `state::get`, `state::update` to
use backticks around "trigger" (i.e., `trigger` `state::set`, `state::get`,
`state::update`), and make the same change for the similar inconsistent
occurrence later (the other table cell on line ~58) so all primitive references
are consistently backticked.
In `@skills/iii-trigger-actions/SKILL.md`:
- Around line 39-44: Replace the one-line reference paragraph with a compact
list of language-specific links to improve readability: convert the sentence
that mixes links into three short items (JS: ../references/trigger-actions.js,
Python: ../references/trigger-actions.py, Rust:
../references/trigger-actions.rs) and append a brief clarifying phrase like
"invocation modes showing sync, void, and enqueue patterns" so the SKILL.md
paragraph reads as a concise list referencing those files.
In `@skills/iii-trigger-conditions/SKILL.md`:
- Around line 39-45: The reference paragraph in SKILL.md is broken by inline
“Also available…” lines; change it to one clear sentence describing the example
(e.g., "See ../references/trigger-conditions.js for the full working example
where a business rule function filters events before the handler processes
them.") followed by a short bullet list of language variants referencing
trigger-conditions.js, trigger-conditions.py, and trigger-conditions.rs; ensure
the clause "where a business rule function filters events before the handler
processes them" remains attached to the main sentence rather than split across
the list.
In `@skills/references/cron-scheduling.py`:
- Around line 61-65: This cron trigger uses a 7-field cron expression via
iii.register_trigger (function_id "cron::hourly-cleanup") but other references
(notably dead-letter-queues.js) use 5-field expressions; align formats across
the repo by updating the 5-field expressions in dead-letter-queues.js to the
documented 7-field format (second minute hour day month weekday year) so all
cron expressions follow the docstring convention — locate cron expressions in
dead-letter-queues.js and expand them to include seconds (and year if used
elsewhere) matching the pattern used by iii.register_trigger.
In `@skills/references/dead-letter-queues.rs`:
- Around line 230-233: The call to iii.shutdown() uses the deprecated
synchronous shutdown pattern; instead of changing behavior, add a brief inline
comment next to the iii.shutdown() invocation explaining that this synchronous
shutdown is used here for brevity and that production code should call the async
variant (e.g., shutdown_async().await) after awaiting tokio::signal::ctrl_c() —
reference the iii.shutdown() call and the preferred shutdown_async().await
method so readers know the recommended replacement.
In `@skills/references/http-endpoints.py`:
- Line 18: The import list in this module includes an unused symbol
TriggerAction; remove TriggerAction from the import statement (leaving
InitOptions, Logger, register_worker) to eliminate the unused import and keep
the example focused—update the import line that currently names TriggerAction so
it no longer references that symbol.
In `@skills/references/http-invoked-functions.rs`:
- Line 20: The file currently imports std::time::Duration but never uses it;
remove the unused import statement to eliminate the warning. Locate the
top-level use declaration referencing Duration in http-invoked-functions.rs and
delete the "use std::time::Duration;" line (or if you actually intended to use
Duration, add the proper usage where needed in the function that requires
timing). Ensure no other references to Duration remain so the file compiles
cleanly.
In `@skills/references/observability.py`:
- Around line 154-156: The signal handler _shutdown currently calls
asyncio.get_event_loop(), which is deprecated without a running loop; change it
to create a fresh event loop, set it as current, run the coroutine
iii.shutdown_otel() on it, then close the loop: create a new loop via
asyncio.new_event_loop(), call asyncio.set_event_loop(loop) (or temporarily use
loop.run_until_complete without setting if you prefer), await/
run_until_complete iii.shutdown_otel(), then loop.close() and finally raise
SystemExit(0); this ensures compatibility on Python 3.10+ and that
iii.shutdown_otel() (a coroutine) runs on a proper event loop.
In `@skills/references/observability.rs`:
- Around line 272-278: The code currently calls the deprecated synchronous API
iii.shutdown() after the tokio::runtime::Runtime::new().unwrap().block_on(...)
block; replace this with the async shutdown API by moving the SDK shutdown into
the async block and calling iii.shutdown_async().await (alongside the existing
#[cfg(feature = "otel")] shutdown_otel().await) so the shutdown is awaited and
telemetry is flushed before exit; remove the deprecated iii.shutdown() call and
ensure the call site is inside the block_on async context where
tokio::signal::ctrl_c().await is handled.
In `@skills/references/queue-processing.rs`:
- Line 23: The import std::time::Duration in
skills/references/queue-processing.rs is unused; either remove the unused use
std::time::Duration; line or actually use Duration where intended (for example
in functions like process_queue or backoff logic) — locate the use statement and
delete it if no timing functionality is needed, or replace/add references to
Duration in the relevant function (e.g., process_queue, handle_item, or
retry/backoff helpers) so the import is utilized.
In `@skills/references/realtime-streams.rs`:
- Around line 364-367: Replace the synchronous shutdown call with the async
shutdown helper: inside the existing Tokio block (the
tokio::runtime::Runtime::new().unwrap().block_on(async { ... })), await the
SDK's async shutdown method instead of calling iii.shutdown(); specifically call
iii.shutdown_async().await from within that async block so the shutdown runs on
the runtime and guarantees telemetry flush before exit.
In `@skills/references/state-management.js`:
- Line 12: The import list in skills/references/state-management.js includes an
unused symbol TriggerAction; remove TriggerAction from the import statement
(leaving registerWorker and Logger) to eliminate the unused import and any
linter warnings, i.e., update the import line that currently references
TriggerAction so it only imports the actually used identifiers.
In `@skills/references/state-management.rs`:
- Around line 7-10: Remove the unused import TriggerAction from the use list in
this module; locate the import statement that declares TriggerAction alongside
register_worker, InitOptions, RegisterFunction, TriggerRequest,
builtin_triggers::*, IIITrigger, and Logger and delete TriggerAction since all
trigger calls use action: None and the symbol is never referenced (ensure no
other code in this file relies on TriggerAction before removing).
In `@skills/references/state-reactions.rs`:
- Line 13: Remove the unused import of std::time::Duration (the Duration symbol)
from the top of the file (the use std::time::Duration; line) or, if you intended
to use it, actually reference Duration in the relevant code path; otherwise
simply delete the import to resolve the unused-import warning.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: b08fc6c8-3b6c-4cf1-b00c-cc5ff2a4ff97
📒 Files selected for processing (79)
AGENTS.mdskills/.gitignoreskills/LICENSEskills/README.mdskills/SKILLS.mdskills/iii-agentic-backend/SKILL.mdskills/iii-channels/SKILL.mdskills/iii-cron-scheduling/SKILL.mdskills/iii-custom-triggers/SKILL.mdskills/iii-dead-letter-queues/SKILL.mdskills/iii-effect-system/SKILL.mdskills/iii-engine-config/SKILL.mdskills/iii-event-driven-cqrs/SKILL.mdskills/iii-functions-and-triggers/SKILL.mdskills/iii-getting-started/SKILL.mdskills/iii-http-endpoints/SKILL.mdskills/iii-http-invoked-functions/SKILL.mdskills/iii-low-code-automation/SKILL.mdskills/iii-node-sdk/SKILL.mdskills/iii-observability/SKILL.mdskills/iii-python-sdk/SKILL.mdskills/iii-queue-processing/SKILL.mdskills/iii-reactive-backend/SKILL.mdskills/iii-realtime-streams/SKILL.mdskills/iii-rust-sdk/SKILL.mdskills/iii-state-management/SKILL.mdskills/iii-state-reactions/SKILL.mdskills/iii-trigger-actions/SKILL.mdskills/iii-trigger-conditions/SKILL.mdskills/iii-workflow-orchestration/SKILL.mdskills/references/agentic-backend.jsskills/references/channels.jsskills/references/channels.pyskills/references/channels.rsskills/references/cron-scheduling.jsskills/references/cron-scheduling.pyskills/references/cron-scheduling.rsskills/references/custom-triggers.jsskills/references/custom-triggers.pyskills/references/custom-triggers.rsskills/references/dead-letter-queues.jsskills/references/dead-letter-queues.pyskills/references/dead-letter-queues.rsskills/references/effect-system.jsskills/references/event-driven-cqrs.jsskills/references/functions-and-triggers.jsskills/references/functions-and-triggers.pyskills/references/functions-and-triggers.rsskills/references/http-endpoints.jsskills/references/http-endpoints.pyskills/references/http-endpoints.rsskills/references/http-invoked-functions.jsskills/references/http-invoked-functions.pyskills/references/http-invoked-functions.rsskills/references/iii-config.yamlskills/references/low-code-automation.jsskills/references/observability.jsskills/references/observability.pyskills/references/observability.rsskills/references/queue-processing.jsskills/references/queue-processing.pyskills/references/queue-processing.rsskills/references/reactive-backend.jsskills/references/realtime-streams.jsskills/references/realtime-streams.pyskills/references/realtime-streams.rsskills/references/state-management.jsskills/references/state-management.pyskills/references/state-management.rsskills/references/state-reactions.jsskills/references/state-reactions.pyskills/references/state-reactions.rsskills/references/trigger-actions.jsskills/references/trigger-actions.pyskills/references/trigger-actions.rsskills/references/trigger-conditions.jsskills/references/trigger-conditions.pyskills/references/trigger-conditions.rsskills/references/workflow-orchestration.js
| - When the external event fires, call `iii.trigger(function_id, event)` to invoke the registered function | ||
| - **unregisterTriggerType** cleans up when the trigger type is no longer needed |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -e
# Expect the SDK types/examples to describe a request-object trigger API.
rg -n -C3 '\btrigger\s*\(' sdk/packages/node/iii/src --glob '*.ts'
rg -n -C1 'iii\.trigger\(' skills/iii-custom-triggers/SKILL.md skills/iii-node-sdk/SKILL.md skills/referencesRepository: iii-hq/iii
Length of output: 50366
Replace all iii.trigger(function_id, event) calls with the request-object form iii.trigger({ function_id, payload }).
The SDK and all reference examples use the structured request form. This SKILL.md currently shows a deprecated positional signature that will cause runtime errors. Applies to lines 19, 27, 37, 55, and 67.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/iii-custom-triggers/SKILL.md` around lines 19 - 20, The SKILL.md uses
the deprecated positional call iii.trigger(function_id, event); update every
usage (lines referencing iii.trigger) to the structured request form
iii.trigger({ function_id, payload }) so the SDK accepts the call; search for
all occurrences of iii.trigger and replace the positional signature with the
object form using keys function_id and payload, and verify any
examples/reference text mention the request-object shape rather than the old
positional parameters; keep mention of unregisterTriggerType as-is.
| description: >- | ||
| Builds composable, pipeable function chains on the iii engine. Use when | ||
| building functional pipelines, effect systems, or typed composition layers | ||
| where each step is a pure function with distributed tracing and retry. |
There was a problem hiding this comment.
Remove retry from the activation description.
This skill is documented as synchronous trigger chaining where failures stop the pipeline. Keeping retry in the description will bias selection toward iii-effect-system for retry/DLQ requests that should land on queue or workflow patterns.
Suggested edit
description: >-
Builds composable, pipeable function chains on the iii engine. Use when
building functional pipelines, effect systems, or typed composition layers
- where each step is a pure function with distributed tracing and retry.
+ where each step is a pure function with distributed tracing.As per coding guidelines, skills are activated via the description field, and iii-effect-system should use TriggerAction.Enqueue({ queue }) or iii-workflow-orchestration for retry-heavy flows.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/iii-effect-system/SKILL.md` around lines 3 - 6, The activation
description in SKILL.md currently mentions "retry", which biases selection for
retry/DLQ scenarios; remove the word "retry" from the description paragraph (the
description: "Builds composable, pipeable function chains... retry.") and
replace or rephrase to clarify synchronous trigger chaining (e.g., mention
failures stop the pipeline) and, if needed, add a note directing retry-heavy
flows to use TriggerAction.Enqueue({ queue }) or the iii-workflow-orchestration
skill instead; update the description string in SKILL.md accordingly.
| ```bash | ||
| # TypeScript / Node.js | ||
| npm install iii-sdk | ||
|
|
There was a problem hiding this comment.
Document the JS install step with pnpm.
Line 49 teaches npm install iii-sdk, which conflicts with the repo-wide docs/skills rules. The getting-started path should use pnpm for JS/TS examples.
💡 Suggested fix
-# TypeScript / Node.js
-npm install iii-sdk
+# TypeScript / Node.js
+pnpm add iii-sdkAs per coding guidelines, "Use pnpm (never npm) for JS/TS."
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ```bash | |
| # TypeScript / Node.js | |
| npm install iii-sdk |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/iii-getting-started/SKILL.md` around lines 47 - 50, Replace the npm
install instruction in the code block in SKILL.md (the TypeScript / Node.js
example) with the pnpm equivalent: change the command that installs iii-sdk to
use pnpm install and update any surrounding text if it references npm; ensure
the example follows repo guideline "Use pnpm (never npm) for JS/TS" so the
TypeScript/Node.js install step consistently uses pnpm across the
getting-started skill.
| ## Install | ||
|
|
||
| `npm install iii-sdk` |
There was a problem hiding this comment.
Use pnpm in the install snippet.
Line 18 uses npm install iii-sdk, which conflicts with the repo’s JS/TS command convention for skills/docs.
🛠️ Suggested fix
-`npm install iii-sdk`
+`pnpm add iii-sdk`As per coding guidelines, "Use pnpm (never npm) for JS/TS."
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ## Install | |
| `npm install iii-sdk` | |
| ## Install | |
| `pnpm add iii-sdk` |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/iii-node-sdk/SKILL.md` around lines 16 - 18, The Install snippet in
SKILL.md currently uses "npm install iii-sdk"; update the documentation to
follow repo convention by replacing that command with the pnpm equivalent ("pnpm
add iii-sdk") in the Install section and any other occurrences; ensure the
Install code block under the "## Install" heading and any related examples use
pnpm (not npm) to comply with the "Use pnpm (never npm) for JS/TS" guideline.
| ## Key Exports | ||
|
|
||
| | Export | Purpose | | ||
| | ------------------------------------------------ | ------------------------------------------- | | ||
| | `registerWorker(url, { workerName })` | Connect to the engine and return the client | | ||
| | `registerFunction({ id }, handler)` | Register an async function handler | | ||
| | `registerTrigger({ type, function_id, config })` | Bind a trigger to a function | | ||
| | `trigger({ function_id, payload, action? })` | Invoke a function | | ||
| | `TriggerAction.Void()` | Fire-and-forget invocation mode | | ||
| | `TriggerAction.Enqueue({ queue })` | Durable async invocation mode | | ||
| | `Logger` | Structured logging | | ||
| | `withSpan`, `getTracer`, `getMeter` | OpenTelemetry instrumentation | | ||
| | `createChannel()` | Binary streaming between workers | | ||
| | `createStream(name, adapter)` | Custom stream implementation | | ||
| | `registerTriggerType(id, handler)` | Custom trigger type registration | | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -e
# Expect top-level exports and worker methods to be distinct in the Node SDK source.
rg -n -C2 'export .*registerWorker|export .*registerFunction|export .*registerTrigger|export .*createStream|export .*registerTriggerType|export .*createChannel' sdk/packages/node/iii/src --glob '*.ts'
rg -n -C2 '\.registerFunction\s*\(|\.registerTrigger\s*\(|\.createStream\s*\(|\.registerTriggerType\s*\(' skills/references sdk/packages/node/iii/srcRepository: iii-hq/iii
Length of output: 50368
🏁 Script executed:
#!/bin/bash
# Find the ISdk interface definition to confirm these are methods on the worker instance
rg -n "interface ISdk|class.*Sdk" sdk/packages/node/iii/src --glob '*.ts' -A 30 | head -100Repository: iii-hq/iii
Length of output: 4899
🏁 Script executed:
#!/bin/bash
# Read the SKILL.md file to see the current table
cat -n skills/iii-node-sdk/SKILL.md | sed -n '20,35p'Repository: iii-hq/iii
Length of output: 1469
🏁 Script executed:
#!/bin/bash
# Get the complete export list from index.ts
cat -n sdk/packages/node/iii/src/index.tsRepository: iii-hq/iii
Length of output: 1408
🏁 Script executed:
#!/bin/bash
# Check ISdk for createStream and registerTriggerType methods
rg -n "createStream|registerTriggerType" sdk/packages/node/iii/src/types.ts -A 5 | head -50Repository: iii-hq/iii
Length of output: 1882
Change section title from "Key Exports" to "Key APIs" and prefix instance methods with iii.
The table mixes a top-level export (registerWorker) with instance methods on the SDK object. Lines 25, 26, 32, and 34 list registerFunction, registerTrigger, createStream, and registerTriggerType without the iii. prefix, incorrectly suggesting they are bare imports. All skill examples use iii.registerFunction(...), iii.registerTrigger(...), etc., so the table should reflect this.
Suggested update
-## Key Exports
+## Key APIs
-| `registerFunction({ id }, handler)` | Register an async function handler |
-| `registerTrigger({ type, function_id, config })` | Bind a trigger to a function |
+| `iii.registerFunction({ id }, handler)` | Register an async function handler |
+| `iii.registerTrigger({ type, function_id, config })` | Bind a trigger to a function |
-| `createChannel()` | Binary streaming between workers |
-| `createStream(name, adapter)` | Custom stream implementation |
-| `registerTriggerType(id, handler)` | Custom trigger type registration |
+| `iii.createChannel()` | Binary streaming between workers |
+| `iii.createStream(name, adapter)` | Custom stream implementation |
+| `iii.registerTriggerType(id, handler)` | Custom trigger type registration |🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/iii-node-sdk/SKILL.md` around lines 20 - 35, Rename the section title
from "Key Exports" to "Key APIs" and update the table to reflect which functions
are top-level vs instance methods: keep registerWorker(...) as a top-level
export but prefix the instance SDK methods with "iii." — specifically change
registerFunction({ id }, handler) to iii.registerFunction(...),
registerTrigger({ type, function_id, config }) to iii.registerTrigger(...),
createStream(name, adapter) to iii.createStream(...), and
registerTriggerType(id, handler) to iii.registerTriggerType(...); leave other
symbols (trigger, TriggerAction.Void/Enqueue, Logger, withSpan, getTracer,
getMeter, createChannel) as-is but verify their ownership is correct in the
table.
| iii.register_trigger({ | ||
| "type": "state", | ||
| "function_id": "integrations::order-webhook", | ||
| "config": {"scope": "orders", "key": "status"}, | ||
| }) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n skills/references/http-invoked-functions.py | sed -n '115,195p'Repository: iii-hq/iii
Length of output: 3029
🏁 Script executed:
rg "register_trigger.*cron" -A 3Repository: iii-hq/iii
Length of output: 7626
🏁 Script executed:
find skills/references -name "*.py" -type f | head -20Repository: iii-hq/iii
Length of output: 584
🏁 Script executed:
rg "register_trigger.*cron" -A 2 skills/references/Repository: iii-hq/iii
Length of output: 36
🏁 Script executed:
grep -r "expression.*\*" skills/references/ | grep -i cronRepository: iii-hq/iii
Length of output: 549
🏁 Script executed:
cat -n skills/references/functions-and-triggers.py | grep -A 5 "cron"Repository: iii-hq/iii
Length of output: 621
🏁 Script executed:
cat -n skills/references/functions-and-triggers.py | sed -n '65,80p'Repository: iii-hq/iii
Length of output: 749
🏁 Script executed:
cat -n skills/references/cron-scheduling.pyRepository: iii-hq/iii
Length of output: 6307
This state trigger never matches the keys written above.
Lines 123 and 135 write state with key data["orderId"], but line 161 filters on the literal key "status". As written, integrations::order-webhook will never receive those updates.
🩹 Minimal fix
iii.register_trigger({
"type": "state",
"function_id": "integrations::order-webhook",
- "config": {"scope": "orders", "key": "status"},
+ "config": {"scope": "orders"},
})📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| iii.register_trigger({ | |
| "type": "state", | |
| "function_id": "integrations::order-webhook", | |
| "config": {"scope": "orders", "key": "status"}, | |
| }) | |
| iii.register_trigger({ | |
| "type": "state", | |
| "function_id": "integrations::order-webhook", | |
| "config": {"scope": "orders"}, | |
| }) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/references/http-invoked-functions.py` around lines 158 - 162, The
state trigger registered via iii.register_trigger for
"integrations::order-webhook" is filtering on the wrong key ("status") so it
never matches the state writes that use data["orderId"]; update the trigger's
config to use the same key used when writing state (i.e., the orderId key)
instead of "status" — replace "key": "status" with the same
expression/identifier used at the state write sites (data["orderId"] or its
evaluated value) so register_trigger(...) will match the state updates sent to
integrations::order-webhook.
| // Fire-and-forget notification | ||
| iii.trigger({ | ||
| function_id: 'notifications::send', | ||
| payload: { type: 'payment_captured', orderId: data.orderId, chargeId }, | ||
| action: TriggerAction.Void(), | ||
| }) |
There was a problem hiding this comment.
Register or replace notifications::send in this example.
Line 86 dispatches notifications::send, but this file never registers that function ID. In a standalone reference, payments::process now depends on some other worker being present, so the example no longer runs end-to-end by itself.
Based on learnings, files under skills/references/ are standalone pattern-demonstration reference files, not production code and not part of any build.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/references/queue-processing.js` around lines 85 - 90, The example
fires a notification to function_id 'notifications::send' but that function
isn't registered in this standalone reference, breaking end-to-end execution;
fix by registering a local handler named 'notifications::send' (or replace the
trigger target with an inline/no-op handler) in this file so the iii.trigger
call has a reachable function: add a registration using the same runtime API
used elsewhere in the file (e.g., iii.registerFunction or iii.handle) with an
async handler that accepts the payload ({ type, orderId, chargeId }) and
performs the illustrative action (log/send) and ensure the handler's signature
and behavior match the fire-and-forget TriggerAction.Void() usage.
| iii.registerFunction({ id: 'conditions::is-high-value' }, async (data) => { | ||
| // data is the same event the handler would receive | ||
| return data.value?.total > 500 | ||
| }) | ||
|
|
||
| // Handler function — only runs when the condition passes | ||
| iii.registerFunction({ id: 'orders::flag-high-value' }, async (data) => { | ||
| const logger = new Logger() | ||
| logger.info('High-value order detected', { key: data.key, total: data.value.total }) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify the state-trigger payload shape used in sibling docs/examples.
# Expected: state-trigger docs and sibling references use `new_value`, not `value`.
rg -n -C2 'new_value|old_value|event_type' skills/iii-state-reactions/SKILL.md skills/references/state-reactions.js skills/references/trigger-conditions.rs skills/references/trigger-conditions.jsRepository: iii-hq/iii
Length of output: 11287
Use the state event's new_value field here.
The state-trigger payload is { new_value, old_value, key, event_type }. Accessing data.value causes the condition to fail silently and the handler to crash when accessing the field.
Suggested edit
iii.registerFunction({ id: 'conditions::is-high-value' }, async (data) => {
// data is the same event the handler would receive
- return data.value?.total > 500
+ return data.new_value?.total > 500
})
// Handler function — only runs when the condition passes
iii.registerFunction({ id: 'orders::flag-high-value' }, async (data) => {
const logger = new Logger()
- logger.info('High-value order detected', { key: data.key, total: data.value.total })
+ logger.info('High-value order detected', { key: data.key, total: data.new_value.total })📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| iii.registerFunction({ id: 'conditions::is-high-value' }, async (data) => { | |
| // data is the same event the handler would receive | |
| return data.value?.total > 500 | |
| }) | |
| // Handler function — only runs when the condition passes | |
| iii.registerFunction({ id: 'orders::flag-high-value' }, async (data) => { | |
| const logger = new Logger() | |
| logger.info('High-value order detected', { key: data.key, total: data.value.total }) | |
| iii.registerFunction({ id: 'conditions::is-high-value' }, async (data) => { | |
| // data is the same event the handler would receive | |
| return data.new_value?.total > 500 | |
| }) | |
| // Handler function — only runs when the condition passes | |
| iii.registerFunction({ id: 'orders::flag-high-value' }, async (data) => { | |
| const logger = new Logger() | |
| logger.info('High-value order detected', { key: data.key, total: data.new_value.total }) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/references/trigger-conditions.js` around lines 27 - 35, The condition
and handler are using the wrong payload field (data.value) — state-trigger
events use { new_value, old_value, key, event_type } — so update the functions
registered as 'conditions::is-high-value' and 'orders::flag-high-value' to read
totals from data.new_value (not data.value) and use optional chaining (e.g.,
data.new_value?.total) to avoid crashes when new_value is missing; ensure the
logger uses data.key and data.new_value?.total for safe logging.
| iii.registerTrigger({ | ||
| type: 'cron', | ||
| function_id: 'reports::weekday-digest', | ||
| config: { | ||
| expression: '0 8 * * *', // runs daily at 08:00 but condition limits to weekdays | ||
| condition_function_id: 'conditions::is-weekday', | ||
| }, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify the repo's cron guidance and inspect this example.
# Expected: AGENTS.md / iii-cron-scheduling say 7-field cron, while this file still shows 5 fields.
rg -n -C2 '7-field format|second minute hour day month weekday year|expression' AGENTS.md skills/iii-cron-scheduling/SKILL.md
rg -n -C2 "expression: '.*'" skills/references/trigger-conditions.jsRepository: iii-hq/iii
Length of output: 5569
Update cron expression to 7-field format.
The expression at line 144 is 5-field (0 8 * * *), but the codebase requires 7-field format per the iii-cron-scheduling skill documentation. Change to 0 0 8 * * * * (sec min hour dom month dow year).
Suggested edit
config: {
- expression: '0 8 * * *', // runs daily at 08:00 but condition limits to weekdays
+ expression: '0 0 8 * * * *', // runs daily at 08:00 but condition limits to weekdays
condition_function_id: 'conditions::is-weekday',
},
})📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| iii.registerTrigger({ | |
| type: 'cron', | |
| function_id: 'reports::weekday-digest', | |
| config: { | |
| expression: '0 8 * * *', // runs daily at 08:00 but condition limits to weekdays | |
| condition_function_id: 'conditions::is-weekday', | |
| }, | |
| iii.registerTrigger({ | |
| type: 'cron', | |
| function_id: 'reports::weekday-digest', | |
| config: { | |
| expression: '0 0 8 * * * *', // runs daily at 08:00 but condition limits to weekdays | |
| condition_function_id: 'conditions::is-weekday', | |
| }, |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/references/trigger-conditions.js` around lines 140 - 146, The cron
expression in the iii.registerTrigger call for function_id
'reports::weekday-digest' uses a 5-field format ("0 8 * * *"); update the
config.expression to the required 7-field format "0 0 8 * * * *" (sec min hour
dom month dow year) so the trigger conforms to the iii-cron-scheduling skill;
keep the rest of the registerTrigger block (type, function_id,
condition_function_id) unchanged.
| iii.register_trigger( | ||
| IIITrigger::Cron( | ||
| CronTriggerConfig::new("0 8 * * *") | ||
| .condition("conditions::is-weekday"), | ||
| ) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify the repo's cron guidance and inspect this example.
# Expected: AGENTS.md / iii-cron-scheduling say 7-field cron, while this file shows a 5-field string.
rg -n -C2 '7-field format|second minute hour day month weekday year|expression' AGENTS.md skills/iii-cron-scheduling/SKILL.md
rg -n -C2 'CronTriggerConfig::new\(".*"\)' skills/references/trigger-conditions.rsRepository: iii-hq/iii
Length of output: 5536
Switch this cron string to the engine's 7-field format.
This is a 5-field schedule; the repo standard is 7-field format (second minute hour day month weekday year).
Suggested edit
iii.register_trigger(
IIITrigger::Cron(
- CronTriggerConfig::new("0 8 * * *")
+ CronTriggerConfig::new("0 0 8 * * * *")
.condition("conditions::is-weekday"),
)
.for_function("reports::weekday-digest"),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| iii.register_trigger( | |
| IIITrigger::Cron( | |
| CronTriggerConfig::new("0 8 * * *") | |
| .condition("conditions::is-weekday"), | |
| ) | |
| iii.register_trigger( | |
| IIITrigger::Cron( | |
| CronTriggerConfig::new("0 0 8 * * * *") | |
| .condition("conditions::is-weekday"), | |
| ) | |
| .for_function("reports::weekday-digest"), |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/references/trigger-conditions.rs` around lines 211 - 215, The cron
expression passed to CronTriggerConfig::new in the iii.register_trigger call
uses a 5-field format ("0 8 * * *"); update it to the engine's 7-field format
(second minute hour day month weekday year) used by CronTriggerConfig, e.g.
change the string to include seconds and year placeholders like "0 0 8 * * * *"
in the IIITrigger::Cron / CronTriggerConfig::new invocation where
.condition("conditions::is-weekday") is set.
Summary
Brings iii-hq/skills into the monorepo at `skills/` using `git subtree add`, preserving the full commit history so diffs are reviewable.
What's in the subtree (from iii-hq/skills)
Additional changes on top
Install
Test plan
Summary by CodeRabbit
Documentation
Examples