Conversation
Co-authored-by: anthonyiscoding <142696453+anthonyiscoding@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThis pull request comprehensively restructures the iii documentation by reorganizing concepts into a new "Primitives & Concepts" section, removing obsolete concept pages, adding eleven new how-to guides covering triggers, workers, and configuration, updating all SDK READMEs with new API patterns, and introducing a configuration reference system with parsing utilities and interactive components. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 13
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (11)
website/components/sections/DependencyVisualization.tsx (1)
814-843:⚠️ Potential issue | 🟡 MinorMake the
initheuristic identifier-aware.Line 841’s
includes("init(")also matches names likeuseInit(andonInit(. SinceisStrongArchitecturewins, those lines will be highlighted as architecture even when they’re ordinary business code.♻️ Suggested change
- lowerLine.includes("init(") || + /(^|[^\w])init\s*\(/.test(lowerLine) ||🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@website/components/sections/DependencyVisualization.tsx` around lines 814 - 843, The heuristic in isStrongArchitecture incorrectly treats any occurrence of "init(" (from includes("init(")) as an architecture signal, matching names like useInit( or onInit(; update the check in the isStrongArchitecture construction to be identifier-aware by replacing the simple includes("init(") with a pattern match on lowerLine that only matches standalone "init(" (e.g., using a regex that enforces word boundaries or non-identifier boundary before "init(") or checking for startsWith("init(") or for a non-alphanumeric char immediately before "init("), keeping the other checks the same; make this change in the same scope where lowerLine and isStrongArchitecture are computed so symbols like lowerLine and isStrongArchitecture are used consistently.website/components/sections/HelloWorldSection.tsx (1)
40-56:⚠️ Potential issue | 🟠 MajorUpdate the Rust code example to match the current iii-sdk API.
The example uses an
initfunction that doesn't match the official iii-sdk documentation. The current API pattern is:
III::new()to create the client (synchronous).connect().await?to establish the WebSocket connection (asynchronous)Replace the initialization with:
let iii = III::new("ws://localhost:49134"); iii.connect().await?;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@website/components/sections/HelloWorldSection.tsx` around lines 40 - 56, The Rust example uses the old init(...) pattern; update the client creation to use the new III API: replace the call to init(...) with creating the client via III::new(...) and then await the connection with .connect().await? (i.e., change the code that currently calls init to call III::new(...) and then call .connect().await? before registering functions like iii.register_function("data.transform", transform);).website/components/MachineView.tsx (1)
79-90:⚠️ Potential issue | 🟡 MinorInconsistent function ID and api_path notation across files.
The SDK examples in this file use dot notation for function IDs (
users.create) and leading slashes for api_path (/users), but other files in this PR use different conventions:
File Function ID api_path MachineView.tsx (SDK examples) users.create/usersEngineSection.tsx users::createusersTerminal.tsx api::echo,math::addechoAdditionally, within this same file at lines 282-283, there's an example using the old pattern:
type: "http", function_id: "api::users", config: { api_path: "users", http_method: "POST" }Consider aligning the notation across all documentation and examples to avoid confusing developers.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@website/components/MachineView.tsx` around lines 79 - 90, The examples in MachineView.tsx use inconsistent function_id and api_path notation (e.g., "users.create" and "/users") versus other examples that use "users::create" and "users" (no leading slash); update all occurrences in this file — including the iii.registerTrigger call, the async function registered for "users.create", and the older example at the spot using "api::users" — to the project's canonical format: use the double-colon namespaced function_id (e.g., "users::create") and api_path without a leading slash (e.g., "users"), ensuring all examples and registerTrigger.config.api_path values and function_id strings match that convention.docs/content/how-to/manage-state.mdx (1)
18-23:⚠️ Potential issue | 🟡 MinorKeep the
KvStorefile_pathexamples consistent.This now shows
./data/state_store.db, while the new reference page uses./data/state_storefor the samemodules::state::adapters::KvStoresetting. Please standardize on one canonical example, or explicitly note that both formats are valid, so readers do not infer different path semantics for the same adapter.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/content/how-to/manage-state.mdx` around lines 18 - 23, The docs show two different example values for the KvStore adapter's file_path (./data/state_store.db vs ./data/state_store); pick one canonical example and update this page to match the other reference page (or add a short note that both filename styles are acceptable), specifically update the modules::state::adapters::KvStore example's file_path entry so it is consistent with the other docs (or add a clarifying sentence after the file_path key explaining both formats are valid).docs/content/how-to/add-background-job.mdx (1)
38-52:⚠️ Potential issue | 🟡 MinorMissing
import osin Python example.The Python code uses
os.environ.get()butosis not imported. This would cause aNameErrorat runtime.import asyncio from iii import III +import os async def main(): iii = III(os.environ.get('III_BRIDGE_URL', 'ws://localhost:49134'))🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/content/how-to/add-background-job.mdx` around lines 38 - 52, The example Python snippet is missing the os import causing a NameError for os.environ.get; add "import os" at the top of the file (above asyncio and III imports) so the main() function and the call to os.environ.get(...) used when instantiating III work correctly; ensure the import is present alongside the existing imports referenced in main, send_welcome, and iii.register_function.docs/content/how-to/react-to-state-changes.mdx (1)
33-33:⚠️ Potential issue | 🟡 MinorTypo: "addrssed" should be "addressed".
This is the same typo appearing in multiple files.
- This will be addrssed shortly so that a single initialization step is all that will be required in all languages. + This will be addressed shortly so that a single initialization step is all that will be required in all languages.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/content/how-to/react-to-state-changes.mdx` at line 33, The docs contain a recurring typo "addrssed" that should be corrected to "addressed"; search for the exact token "addrssed" (e.g., in docs/content/how-to/react-to-state-changes.mdx) and replace it with "addressed" across all files where it appears to ensure consistency.docs/content/how-to/schedule-cron-task.mdx (1)
28-28:⚠️ Potential issue | 🟡 MinorTypo: "addrssed" should be "addressed".
- This will be addrssed shortly so that a single initialization step is all that will be required in all languages. + This will be addressed shortly so that a single initialization step is all that will be required in all languages.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/content/how-to/schedule-cron-task.mdx` at line 28, Fix the typo in the sentence "This will be addrssed shortly so that a single initialization step is all that will be required in all languages." by replacing "addrssed" with the correct spelling "addressed" so the sentence reads "This will be addressed shortly..." in the document content.docs/content/how-to/queue-background-job.mdx (1)
64-72:⚠️ Potential issue | 🟡 MinorMissing
import osin Python example.The Python code uses
os.environ.get()at line 70 but theosmodule is not imported. Add it to the imports:import asyncio import uuid from iii import III, InitOptions, ApiRequest, ApiResponse, get_context +import os iii = III( address=os.environ.get('III_BRIDGE_URL', 'ws://localhost:49134'),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/content/how-to/queue-background-job.mdx` around lines 64 - 72, The Python example is missing the os import used by os.environ.get(); add "import os" to the top imports (near existing imports for asyncio, uuid and symbols like III, InitOptions, ApiRequest, ApiResponse, get_context) so the call to os.environ.get('III_BRIDGE_URL', ...) works without a NameError.docs/content/how-to/use-functions-and-triggers.mdx (1)
16-19:⚠️ Potential issue | 🟡 MinorFix typo: "addrssed" → "addressed".
✏️ Proposed fix
<Callout title="Persistence in Python & Rust APIs" type="info"> You may notice that currently the Node API has no code around persistence while Python and Rust do. -This will be addrssed shortly so that a single initialization step is all that will be required in all languages. +This will be addressed shortly so that a single initialization step is all that will be required in all languages. </Callout>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/content/how-to/use-functions-and-triggers.mdx` around lines 16 - 19, Replace the misspelled word "addrssed" with "addressed" inside the Callout block titled "Persistence in Python & Rust APIs" (the sentence that currently reads "This will be addrssed shortly...") so the text reads "This will be addressed shortly so that a single initialization step is all that will be required in all languages."website/components/sections/AgentReadySection.tsx (2)
59-98:⚠️ Potential issue | 🟠 MajorFinish the naming/API migration across the rest of this carousel.
These updates move only two tabs to dot-delimited ids and
init(...), while the othercapabilitiesentries below still renderagents::...,orders::...,chat::..., etc. The page now presents two incompatible conventions side-by-side, so examples copied from different tabs will not line up.Also applies to: 260-315
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@website/components/sections/AgentReadySection.tsx` around lines 59 - 98, Continue the naming/API migration by converting the remaining capability examples in AgentReadySection (the capabilities entries that still use 'agents::...', 'orders::...', 'chat::...' etc.) to the new dot-delimited ids (e.g., 'agent.research' style) and standardize the init API usage to init(...) in all language snippets; specifically update the capabilities array entries and every example snippet that references old names or calls (look for strings like "agents::", "orders::", "chat::" and for any init variants) so they use the new dot-delimited ids and the init(...) form consistently across all tabs (also apply same changes to the other block range mentioned).
58-69:⚠️ Potential issue | 🟠 MajorUse
letforresponsein the TypeScript sample.Line 61 declares
responseasconst, but line 69 reassigns it inside the while loop. This causes a TypeScript compilation error and prevents the code from running.Proposed fix
- const response = await callLLM(query, { tools }) + let response = await callLLM(query, { tools })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@website/components/sections/AgentReadySection.tsx` around lines 58 - 69, In the iii.registerFunction handler for id "agent.research", the variable response (created from callLLM) must be mutable because it’s reassigned inside the while loop; change its declaration from const to let in the async ({ query }) => { ... } function where callLLM is called (references: iii.registerFunction, callLLM, response, while (response.toolCall), iii.trigger) so the subsequent assignment response = await callLLM(...) compiles correctly.
🧹 Nitpick comments (17)
engine/README.md (1)
23-23: Consider varying sentence structure for improved flow.The Function description uses three successive sentences starting with "It," which creates a somewhat repetitive pattern. While the parallel structure aids scannability in a table format, you might consider consolidating to reduce repetition.
♻️ Optional style refinement
-| **Function** | A unit of work. It receives input and optionally returns output. It can exist anywhere: locally, in the cloud, on serverless, or as a third-party HTTP endpoint. It can mutate state, invoke other functions, and modify databases. | +| **Function** | A unit of work that receives input and optionally returns output. Can exist anywhere: locally, in the cloud, on serverless, or as a third-party HTTP endpoint. Can mutate state, invoke other functions, and modify databases. |🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@engine/README.md` at line 23, The "Function" table entry is repetitive with three sentences all starting "It"; update the Function description in the README table to consolidate clauses and vary sentence structure—combine related actions into one or two sentences (for example, merge "It receives input and optionally returns output" with "It can exist anywhere..." and then list capabilities like mutating state, invoking other functions, and modifying databases) so the entry reads more fluidly while preserving all original information..cursor/rules/docs.mdc (1)
47-49: Make the banned-word rule more objective.
"slop words"is catchy, but it is too subjective for a shared authoring rule. Prefer a concrete instruction like “avoid vague or inflated wording” plus a short do/don’t list so different contributors apply it consistently.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.cursor/rules/docs.mdc around lines 47 - 49, Update the "Branding and Voice" rule to replace the subjective term "slop words" with a concrete rule like "avoid vague or inflated wording", modify the bullet that currently reads '- Avoid "slop" words which are unnecessary or less concrete terminology (example: stitching (slop) versus connecting (accurate))' to state the new instruction, and add a brief do/don't sublist with specific examples (e.g., Do: use specific verbs like "connect"; Don't: use vague/marketingy terms like "stitching", "leverage") so contributors can apply the rule consistently; keep the existing note that '"iii" is always lowercase' unchanged.docs/content/primitives-and-concepts/discovery.mdx (1)
3-13: Add one sentence clarifying that Discovery is a concept, not a primitive.The intro jumps straight into behavior, which makes the new section title do a lot of work. A brief framing sentence up front would help readers understand why this page lives under “Primitives & Concepts” without implying Discovery is a third primitive.
Based on learnings, "primitives" and "concepts" are intentionally different terms in this repo: Function and Trigger are the core primitives, while Discovery is a concept.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/content/primitives-and-concepts/discovery.mdx` around lines 3 - 13, Add a single framing sentence at the top of the section clarifying that "Discovery" is a conceptual behavior of the system rather than a core primitive; insert this immediately after the header/intro (before the paragraph that begins "When a worker connects...") and word it succinctly like: "Discovery is a system concept, not a primitive — unlike Function and Trigger, it describes how the engine shares and updates function metadata across workers." Ensure the sentence explicitly contrasts Discovery with the primitives "Function" and "Trigger" so readers understand why this page is under Primitives & Concepts.docs/content/how-to/use-trigger-conditions.mdx (2)
47-47: Inconsistent: hardcoded URL instead of environment variable.Other how-to pages in this PR use
os.environ.get('III_BRIDGE_URL', 'ws://localhost:49134'). This example should follow the same pattern for consistency.-iii = III("ws://localhost:49134") +import os + +iii = III(os.environ.get('III_BRIDGE_URL', 'ws://localhost:49134'))🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/content/how-to/use-trigger-conditions.mdx` at line 47, The example hardcodes the bridge URL when constructing III("ws://localhost:49134"); change it to use the same environment-variable pattern used elsewhere by reading the III_BRIDGE_URL env var with a fallback (e.g., os.environ.get('III_BRIDGE_URL', 'ws://localhost:49134')) and pass that variable into III(...), so the III constructor call uses the env-driven URL instead of the literal string.
76-76: Inconsistent: hardcoded URL in Rust example.For consistency with other how-to pages, use the environment variable pattern:
- let iii = III::new("ws://127.0.0.1:49134"); + let url = std::env::var("III_BRIDGE_URL").unwrap_or_else(|_| "ws://127.0.0.1:49134".to_string()); + let iii = III::new(&url);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/content/how-to/use-trigger-conditions.mdx` at line 76, Replace the hardcoded WebSocket URL passed to III::new with the environment-variable pattern used elsewhere: read the URI from an environment variable (e.g., std::env::var("LANCE_WEBSOCKET_URI") or similar) and pass that value into III::new (falling back or handling errors consistently with other docs examples).docs/content/how-to/create-custom-trigger-type.mdx (1)
38-49: Note: Express doesn't support dynamic route removal.The
unregisterTriggercallback removes the path from theroutesMap but doesn't actually remove the Express route. Express doesn't natively support removing routes after they're added. The route handler will still exist and potentially cause issues.This is a documentation example, but consider adding a comment noting this limitation, or using a middleware pattern that checks the
routesmap before handling:app.post('*', async (req, res, next) => { const functionId = routes.get(req.path) if (!functionId) return next() const result = await iii.trigger(functionId, req.body) res.json(result) })This pattern would respect route removals since it checks the map on each request.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/content/how-to/create-custom-trigger-type.mdx` around lines 38 - 49, The unregisterTrigger implementation only deletes the path from the routes Map but does not remove the Express route, so the handler registered in registerTrigger (app.post(config.path, ...)) will continue to run; update the docs/example around webhookHandler (and mention registerTrigger, unregisterTrigger, routes, app.post and iii.trigger) to either (a) add a clear note explaining Express cannot remove routes dynamically or (b) change the example to use a single wildcard middleware that checks routes.get(req.path) on each request and calls iii.trigger only when a functionId exists, ensuring route removals are respected; include a short comment explaining why the middleware pattern is necessary.docs/content/how-to/create-ephemeral-worker.mdx (1)
115-117: Redundant log messages.Lines 115 and 117 both log "Task completed" messages, which is redundant:
console.log("Task completed", result.status_code, result.body) console.log("Task completed. Shutting down worker...")Consider removing one or differentiating them more clearly.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/content/how-to/create-ephemeral-worker.mdx` around lines 115 - 117, The two consecutive console.log calls in the ephemeral worker example are redundant: the first logs "Task completed" with result.status_code and result.body, and the second logs "Task completed. Shutting down worker...". Remove or consolidate them by keeping the informative log that includes result.status_code and result.body (the line referencing result.status_code and result.body) and replace the second message with a single clear shutdown log (e.g., "Shutting down worker...") or merge both into one message that includes status/body plus shutdown intent so the code paths using those console.log statements are no longer duplicative.docs/src/lib/components/ConfigReference.tsx (1)
176-180: Add error handling for clipboard operation.
navigator.clipboard.writeTextcan throw if clipboard access is denied or unavailable. Consider wrapping in try-catch to prevent unhandled rejections.🛡️ Proposed fix
const handleCopy = async () => { - await navigator.clipboard.writeText(text) - setCopied(true) - setTimeout(() => setCopied(false), 2000) + try { + await navigator.clipboard.writeText(text) + setCopied(true) + setTimeout(() => setCopied(false), 2000) + } catch { + console.error('Failed to copy to clipboard') + } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/src/lib/components/ConfigReference.tsx` around lines 176 - 180, The handleCopy function calls navigator.clipboard.writeText which can reject; wrap the await call in a try-catch inside handleCopy to prevent unhandled rejections, log or report the error (e.g., console.error or showing a UI error) and only setCopied(true) when the write succeeds; ensure setTimeout to reset copied still runs or is guarded so state remains consistent on failure.docs/src/lib/config-toc.ts (1)
31-33: Consider logging errors for easier debugging.Silent failure makes it hard to diagnose issues when the config file is missing or malformed. Consider logging the error before returning the empty array.
✏️ Add error logging
- } catch { + } catch (error) { + console.warn('Failed to generate config reference TOC:', error) return [] }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/src/lib/config-toc.ts` around lines 31 - 33, The catch block in docs/src/lib/config-toc.ts currently swallows errors and returns an empty array; update it to accept the caught error (e.g., catch (err)) and log the error before returning ([]). Use the project's logging mechanism if available (or console.error) and include contextual text like "Failed to load config TOC:" plus the error to aid debugging; keep the final behavior of returning an empty array unchanged.docs/content/index.mdx (1)
7-7: Consider removing redundant "together"."Connecting together" is redundant—"connecting" alone conveys the same meaning.
✏️ Suggested fix
-Today building a typical backend today means connecting together many separate systems: +Today building a typical backend means connecting many separate systems:Note: This also removes the duplicate "today" which appears twice in the sentence.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/content/index.mdx` at line 7, Edit the sentence "Today building a typical backend today means connecting together many separate systems:" in docs/content/index.mdx: remove the duplicated "today" and the redundant word "together" so it reads succinctly (e.g., "Building a typical backend today means connecting many separate systems:"); ensure punctuation and capitalization remain consistent with surrounding text.docs/src/lib/config-parser.ts (1)
249-251: Consider handling edge cases in slugification.The current implementation may produce empty strings or strings starting with hyphens for edge-case inputs (e.g., names starting with numbers or special characters only).
✏️ More robust slugification
export function slugifyModuleName(name: string): string { - return name.toLowerCase().replace(/[^a-z0-9]/g, '-') + return name + .toLowerCase() + .replace(/[^a-z0-9]+/g, '-') + .replace(/^-+|-+$/g, '') + || 'module' }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/src/lib/config-parser.ts` around lines 249 - 251, slugifyModuleName currently just lowercases and replaces non-alphanumerics with hyphens which can produce empty strings or results starting/ending with hyphens or digits; update slugifyModuleName to (1) collapse multiple hyphens into a single '-', (2) trim leading and trailing hyphens, (3) if the result is empty, return a safe default like 'module' or a deterministic fallback, and (4) if the slug starts with a digit, prefix it (e.g., 'm-') so it never begins with a number; locate and modify slugifyModuleName to apply these steps.docs/content/how-to/iii-config.yaml (4)
280-284: Remove deprecatedlog_levelfield from the reference config.Both
levelandlog_levelare set to the same value, withlog_levelmarked as deprecated. Showing both in the reference config may confuse users. Consider removing the deprecated field or clearly commenting it as legacy.# Engine console log level. Options: trace, debug, info, warn, error # trace = most verbose, error = only errors. level: info - # Alias for level (deprecated, use level instead). - log_level: info + # Deprecated: log_level is an alias for level (use level instead). + # log_level: info🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/content/how-to/iii-config.yaml` around lines 280 - 284, The reference YAML includes both the active "level" field and the deprecated "log_level" alias which is confusing; remove the deprecated "log_level: info" entry from the config snippet (or if you prefer to keep it for legacy readers, convert it into a clear commented legacy note) and update the surrounding comment to only document "level" as the supported setting, leaving "level" unchanged; target the YAML keys "level" and "log_level" in the snippet for the edit.
40-42: Consider noting thatauth_functionis optional or providing a fallback example.The comment on lines 40-41 explains that setting to
nullor omitting allows all connections, but the default valuestream.authimplies a function must exist. Users may get errors if this function isn't registered.Suggested clarification
# Function that validates stream connection/subscription requests (e.g., auth checks). # Set to null or omit to allow all connections. - auth_function: stream.auth + # auth_function: stream.auth # Uncomment and implement to enable auth🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/content/how-to/iii-config.yaml` around lines 40 - 42, Update the documentation to clarify that auth_function is optional and can be set to null or omitted to allow all connections; explicitly mention that the default value stream.auth requires a corresponding registered function and may cause errors if absent, and add a short fallback example or note showing how to set auth_function: null (or register a simple stream.auth implementation) so users know how to avoid missing-function errors.
19-22: CORSallowed_originsshould include protocol and port.The value
localhostalone may not match browser origin headers, which include protocol and port (e.g.,http://localhost:3000). Consider using complete origins or wildcards.cors: allowed_origins: - - localhost + - http://localhost:3000 + # Or use '*' for development; restrict in production🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/content/how-to/iii-config.yaml` around lines 19 - 22, The CORS setting under cors.allowed_origins currently uses the bare value "localhost", which won't match browser origin headers; update cors.allowed_origins to use full origins (e.g., "http://localhost:3000" or "https://example.com") or use wildcard patterns like "*" or "http://localhost:*" as appropriate so the origin includes protocol and port instead of just "localhost".
353-364: Document what telemetry data is collected.Telemetry is enabled by default (
enabled: true). Users should understand what anonymous data is collected to make an informed decision about opting out. Consider adding a brief note or linking to a privacy policy.# Telemetry module - anonymous product usage analytics for iii development. # Helps the team understand usage patterns and prioritize features. + # Data collected: version info, feature usage counts, error rates (no PII). + # See https://iii.dev/privacy for details. - class: modules::telemetry::TelemetryModule🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/content/how-to/iii-config.yaml` around lines 353 - 364, Add a short description under the TelemetryModule block clarifying what anonymous data is collected and where to find the privacy policy; specifically update the YAML block for class: modules::telemetry::TelemetryModule to include a new doc field or comment next to enabled, api_key, sdk_api_key, and heartbeat_interval_secs that lists the categories of data collected (e.g., usage events, heartbeat timestamps, SDK event metadata, no PII) and add a link or reference to the privacy policy or docs page so users can make an informed opt-out decision.docs/content/how-to/dead-letter-queues.mdx (1)
154-160: Document all supportedbackoffTypeoptions.The table shows
backoffTypewith default"exponential"but only lists this one option. If other strategies are supported (e.g.,linear,fixed), document them. If onlyexponentialis supported, clarify this explicitly.-| `backoffType` | `string` | `"exponential"` | Backoff strategy (`exponential`) | +| `backoffType` | `string` | `"exponential"` | Backoff strategy. Currently only `exponential` is supported. |🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/content/how-to/dead-letter-queues.mdx` around lines 154 - 160, The docs currently list backoffType with default "exponential" but don't enumerate supported strategies; update the dead-letter-queue table and surrounding text to either (A) list every supported backoffType option (e.g., "exponential", "linear", "fixed", etc.) and briefly state what each does and their default behavior, or (B) if only exponential is implemented, explicitly note that "exponential" is the only supported backoffType and remove any implication of others; target the backoffType row/description in the table (the `backoffType` field) and any explanatory paragraph that references retry/backoff behavior so readers can see the full set of options or the explicit single-option restriction.docs/content/primitives-and-concepts/index.mdx (1)
8-8: Link text could be clearer.The phrase "learning the primitives and concepts" links only to the primitives page, which may not cover all concepts. Consider adjusting the link text or adding a link to Discovery.
-We recommend learning the [primitives](/docs/primitives-and-concepts/functions-triggers-workers) and concepts behind iii before going deeper. +We recommend learning the [primitives](/docs/primitives-and-concepts/functions-triggers-workers) and [concepts](/docs/primitives-and-concepts/discovery) behind iii before going deeper.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/content/primitives-and-concepts/index.mdx` at line 8, Update the sentence that currently links only "primitives" (the text "learning the [primitives](/docs/primitives-and-concepts/functions-triggers-workers)") so the link accurately reflects what it points to: either change the link text to "primitives and concepts" if the target covers both, or split into two links (e.g., "primitives" linking to /docs/primitives-and-concepts/functions-triggers-workers and "Discovery" linking to the Discovery page) so readers can navigate to both topics; edit the displayed text and target URLs accordingly where the phrase "learning the [primitives](/docs/primitives-and-concepts/functions-triggers-workers)" appears.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.cursor/rules/docs.mdc:
- Around line 38-39: Update the docs rule that currently targets the glob
"docs/**/*.{md,mdx}" so it only matches MDX files by changing the pattern to
"docs/**/*.mdx"; this narrows enforcement to files where the JSX <Tabs>
component is valid and prevents suggesting <Tabs> usage in plain .md files,
while otherwise keeping the existing requirement to include all supported SDKs
(Node/TypeScript, Python, Rust) and keep examples functionally identical across
languages.
In `@docs/content/how-to/configure-engine.mdx`:
- Around line 68-76: Fix the copy in the "Production" section and the Callout
titled "Dont use in_memory in production": change "Dont" to "Don't", replace
"built for purpose" with "purpose-built", and rewrite the Callout body into two
clear sentences (e.g., "Do not use in_memory storage in production. in_memory
storage does not persist between engine restarts and can cause irrecoverable
data loss.") — update the Callout component and the surrounding paragraph text
to use the corrected wording and punctuation.
In `@docs/content/how-to/create-custom-trigger-type.mdx`:
- Line 6: Update the TODO comment that currently reads "proper usecases" to
"proper use cases" so the phrase is two words; locate the comment containing
"{/* TODO: Hold off until we have clarity from the devs on proper usecases. Then
adjust and test. */}" and change "usecases" to "use cases" in that string (keep
the rest of the comment unchanged).
In `@docs/content/how-to/create-ephemeral-worker.mdx`:
- Around line 68-96: The Rust example's worker.rs snippet is missing the closing
portion of the main() function (unclosed braces) and the call to connect the III
client, which makes the block incomplete; fix by either completing main() in
this snippet—after registering the function call iii.connect().await? and then
closing the async main with the appropriate braces and Result return—or, if you
intend to continue in Step 2, add a clear inline note such as “// continued in
Step 2...” at the end of the iii.register_function block so readers know the
snippet is intentionally partial; reference the main() function,
iii.register_function("reports::generate", ...), and iii.connect().await? to
locate where to apply the change.
In `@docs/content/how-to/dead-letter-queues.mdx`:
- Around line 76-78: Remove the visible TODO comment block ("TODO: Update this
once the new way to specify queues is implemented...") from the rendered MDX;
either replace it with final guidance on how to specify queues (e.g., explain
the new syntax like queue: "queue-name" and where queues are configured) or
delete the placeholder entirely so the remark does not appear in published
output.
- Around line 15-17: Remove the visible TODO comment block about the assertion
on non-2xx status calls from the documentation (the comment starting "TODO:
Check if this assertion on non-2xx status calls is correct...") before
publishing; either delete it entirely or replace it with a finalized explanation
or resolved guidance that states whether the assertion is correct and how to
handle non-2xx/3xx statuses (or move any remaining unresolved discussion into a
contributor/developer note or issue tracker link).
- Around line 128-137: The wording in the docs uses "retries" inaccurately;
update the sentence that currently reads "When the payment endpoint is down and
all 5 retries exhaust..." to use "delivery attempts" (or "attempts") to match
the system's semantics where maxRetries represents total delivery attempts (see
maxRetries and log message attempts=5); locate the sentence by searching for
that exact phrase and replace "retries" with "delivery attempts" so the text
reads e.g. "When the payment endpoint is down and all 5 delivery attempts are
exhausted, the engine:".
In `@docs/content/how-to/use-trigger-conditions.mdx`:
- Around line 60-63: The example uses an undefined ApiResponse class
(ApiResponse(statusCode=200, body={...})); either import/define ApiResponse or,
to match other examples, change the return to a plain Python dict with the same
keys (e.g., return {"statusCode": 200, "body": {"processed": True, "amount":
amount}}) so the snippet is self-contained and consistent; update the example
around the return statement that references ApiResponse accordingly.
In `@docs/content/primitives-and-concepts/functions-triggers-workers.mdx`:
- Line 23: Replace the misspelled word "invokation" with the correct spelling
"invocation" in the sentence that reads "the same access to invokation, state,
and other engine functionality as other Functions do." so it becomes "the same
access to invocation, state, and other engine functionality as other Functions
do."
- Line 50: Replace the phrase "iii powered application" with the hyphenated
compound adjective "iii-powered application" in the content where the string
"iii powered" appears so the compound modifier is grammatically correct; search
for the exact token "iii powered" in the functions-triggers-workers.mdx content
and update it to "iii-powered".
In `@docs/content/primitives-and-concepts/index.mdx`:
- Line 6: The line that lists core concepts currently reads "Function, Trigger,
and Worker." Update this wording to match project terminology by replacing
"Worker" with "Discovery" (i.e., make the three core concepts "Function,
Trigger, and Discovery") or, if the intent is that "Worker" is now a core
concept, coordinate with the docs team and update other references accordingly;
locate the string "Function, Trigger, and Worker" in the primitives-and-concepts
content (index.mdx) and change it to "Function, Trigger, and Discovery" to
restore consistent terminology.
In `@website/components/sections/AgentReadySection.tsx`:
- Around line 74-76: The Python examples in AgentReadySection.tsx call
os.environ.get(...) but never import os, causing a NameError; update both Python
snippets that show "from iii import init, get_context" and "iii =
init(os.environ.get(...))" to include an import os line at the top of each
snippet so os.environ is defined.
- Around line 91-98: The Rust example is missing the RegisterFunctionInput
import used when constructing RegisterFunctionInput {...}; update the import
list (which currently includes init, InitOptions, get_context) to also import
RegisterFunctionInput so the example compiles; locate the import statement that
references iii_sdk::{init, InitOptions, get_context} and add
RegisterFunctionInput to that brace-enclosed list.
---
Outside diff comments:
In `@docs/content/how-to/add-background-job.mdx`:
- Around line 38-52: The example Python snippet is missing the os import causing
a NameError for os.environ.get; add "import os" at the top of the file (above
asyncio and III imports) so the main() function and the call to
os.environ.get(...) used when instantiating III work correctly; ensure the
import is present alongside the existing imports referenced in main,
send_welcome, and iii.register_function.
In `@docs/content/how-to/manage-state.mdx`:
- Around line 18-23: The docs show two different example values for the KvStore
adapter's file_path (./data/state_store.db vs ./data/state_store); pick one
canonical example and update this page to match the other reference page (or add
a short note that both filename styles are acceptable), specifically update the
modules::state::adapters::KvStore example's file_path entry so it is consistent
with the other docs (or add a clarifying sentence after the file_path key
explaining both formats are valid).
In `@docs/content/how-to/queue-background-job.mdx`:
- Around line 64-72: The Python example is missing the os import used by
os.environ.get(); add "import os" to the top imports (near existing imports for
asyncio, uuid and symbols like III, InitOptions, ApiRequest, ApiResponse,
get_context) so the call to os.environ.get('III_BRIDGE_URL', ...) works without
a NameError.
In `@docs/content/how-to/react-to-state-changes.mdx`:
- Line 33: The docs contain a recurring typo "addrssed" that should be corrected
to "addressed"; search for the exact token "addrssed" (e.g., in
docs/content/how-to/react-to-state-changes.mdx) and replace it with "addressed"
across all files where it appears to ensure consistency.
In `@docs/content/how-to/schedule-cron-task.mdx`:
- Line 28: Fix the typo in the sentence "This will be addrssed shortly so that a
single initialization step is all that will be required in all languages." by
replacing "addrssed" with the correct spelling "addressed" so the sentence reads
"This will be addressed shortly..." in the document content.
In `@docs/content/how-to/use-functions-and-triggers.mdx`:
- Around line 16-19: Replace the misspelled word "addrssed" with "addressed"
inside the Callout block titled "Persistence in Python & Rust APIs" (the
sentence that currently reads "This will be addrssed shortly...") so the text
reads "This will be addressed shortly so that a single initialization step is
all that will be required in all languages."
In `@website/components/MachineView.tsx`:
- Around line 79-90: The examples in MachineView.tsx use inconsistent
function_id and api_path notation (e.g., "users.create" and "/users") versus
other examples that use "users::create" and "users" (no leading slash); update
all occurrences in this file — including the iii.registerTrigger call, the async
function registered for "users.create", and the older example at the spot using
"api::users" — to the project's canonical format: use the double-colon
namespaced function_id (e.g., "users::create") and api_path without a leading
slash (e.g., "users"), ensuring all examples and registerTrigger.config.api_path
values and function_id strings match that convention.
In `@website/components/sections/AgentReadySection.tsx`:
- Around line 59-98: Continue the naming/API migration by converting the
remaining capability examples in AgentReadySection (the capabilities entries
that still use 'agents::...', 'orders::...', 'chat::...' etc.) to the new
dot-delimited ids (e.g., 'agent.research' style) and standardize the init API
usage to init(...) in all language snippets; specifically update the
capabilities array entries and every example snippet that references old names
or calls (look for strings like "agents::", "orders::", "chat::" and for any
init variants) so they use the new dot-delimited ids and the init(...) form
consistently across all tabs (also apply same changes to the other block range
mentioned).
- Around line 58-69: In the iii.registerFunction handler for id
"agent.research", the variable response (created from callLLM) must be mutable
because it’s reassigned inside the while loop; change its declaration from const
to let in the async ({ query }) => { ... } function where callLLM is called
(references: iii.registerFunction, callLLM, response, while (response.toolCall),
iii.trigger) so the subsequent assignment response = await callLLM(...) compiles
correctly.
In `@website/components/sections/DependencyVisualization.tsx`:
- Around line 814-843: The heuristic in isStrongArchitecture incorrectly treats
any occurrence of "init(" (from includes("init(")) as an architecture signal,
matching names like useInit( or onInit(; update the check in the
isStrongArchitecture construction to be identifier-aware by replacing the simple
includes("init(") with a pattern match on lowerLine that only matches standalone
"init(" (e.g., using a regex that enforces word boundaries or non-identifier
boundary before "init(") or checking for startsWith("init(") or for a
non-alphanumeric char immediately before "init("), keeping the other checks the
same; make this change in the same scope where lowerLine and
isStrongArchitecture are computed so symbols like lowerLine and
isStrongArchitecture are used consistently.
In `@website/components/sections/HelloWorldSection.tsx`:
- Around line 40-56: The Rust example uses the old init(...) pattern; update the
client creation to use the new III API: replace the call to init(...) with
creating the client via III::new(...) and then await the connection with
.connect().await? (i.e., change the code that currently calls init to call
III::new(...) and then call .connect().await? before registering functions like
iii.register_function("data.transform", transform);).
---
Nitpick comments:
In @.cursor/rules/docs.mdc:
- Around line 47-49: Update the "Branding and Voice" rule to replace the
subjective term "slop words" with a concrete rule like "avoid vague or inflated
wording", modify the bullet that currently reads '- Avoid "slop" words which are
unnecessary or less concrete terminology (example: stitching (slop) versus
connecting (accurate))' to state the new instruction, and add a brief do/don't
sublist with specific examples (e.g., Do: use specific verbs like "connect";
Don't: use vague/marketingy terms like "stitching", "leverage") so contributors
can apply the rule consistently; keep the existing note that '"iii" is always
lowercase' unchanged.
In `@docs/content/how-to/create-custom-trigger-type.mdx`:
- Around line 38-49: The unregisterTrigger implementation only deletes the path
from the routes Map but does not remove the Express route, so the handler
registered in registerTrigger (app.post(config.path, ...)) will continue to run;
update the docs/example around webhookHandler (and mention registerTrigger,
unregisterTrigger, routes, app.post and iii.trigger) to either (a) add a clear
note explaining Express cannot remove routes dynamically or (b) change the
example to use a single wildcard middleware that checks routes.get(req.path) on
each request and calls iii.trigger only when a functionId exists, ensuring route
removals are respected; include a short comment explaining why the middleware
pattern is necessary.
In `@docs/content/how-to/create-ephemeral-worker.mdx`:
- Around line 115-117: The two consecutive console.log calls in the ephemeral
worker example are redundant: the first logs "Task completed" with
result.status_code and result.body, and the second logs "Task completed.
Shutting down worker...". Remove or consolidate them by keeping the informative
log that includes result.status_code and result.body (the line referencing
result.status_code and result.body) and replace the second message with a single
clear shutdown log (e.g., "Shutting down worker...") or merge both into one
message that includes status/body plus shutdown intent so the code paths using
those console.log statements are no longer duplicative.
In `@docs/content/how-to/dead-letter-queues.mdx`:
- Around line 154-160: The docs currently list backoffType with default
"exponential" but don't enumerate supported strategies; update the
dead-letter-queue table and surrounding text to either (A) list every supported
backoffType option (e.g., "exponential", "linear", "fixed", etc.) and briefly
state what each does and their default behavior, or (B) if only exponential is
implemented, explicitly note that "exponential" is the only supported
backoffType and remove any implication of others; target the backoffType
row/description in the table (the `backoffType` field) and any explanatory
paragraph that references retry/backoff behavior so readers can see the full set
of options or the explicit single-option restriction.
In `@docs/content/how-to/iii-config.yaml`:
- Around line 280-284: The reference YAML includes both the active "level" field
and the deprecated "log_level" alias which is confusing; remove the deprecated
"log_level: info" entry from the config snippet (or if you prefer to keep it for
legacy readers, convert it into a clear commented legacy note) and update the
surrounding comment to only document "level" as the supported setting, leaving
"level" unchanged; target the YAML keys "level" and "log_level" in the snippet
for the edit.
- Around line 40-42: Update the documentation to clarify that auth_function is
optional and can be set to null or omitted to allow all connections; explicitly
mention that the default value stream.auth requires a corresponding registered
function and may cause errors if absent, and add a short fallback example or
note showing how to set auth_function: null (or register a simple stream.auth
implementation) so users know how to avoid missing-function errors.
- Around line 19-22: The CORS setting under cors.allowed_origins currently uses
the bare value "localhost", which won't match browser origin headers; update
cors.allowed_origins to use full origins (e.g., "http://localhost:3000" or
"https://example.com") or use wildcard patterns like "*" or "http://localhost:*"
as appropriate so the origin includes protocol and port instead of just
"localhost".
- Around line 353-364: Add a short description under the TelemetryModule block
clarifying what anonymous data is collected and where to find the privacy
policy; specifically update the YAML block for class:
modules::telemetry::TelemetryModule to include a new doc field or comment next
to enabled, api_key, sdk_api_key, and heartbeat_interval_secs that lists the
categories of data collected (e.g., usage events, heartbeat timestamps, SDK
event metadata, no PII) and add a link or reference to the privacy policy or
docs page so users can make an informed opt-out decision.
In `@docs/content/how-to/use-trigger-conditions.mdx`:
- Line 47: The example hardcodes the bridge URL when constructing
III("ws://localhost:49134"); change it to use the same environment-variable
pattern used elsewhere by reading the III_BRIDGE_URL env var with a fallback
(e.g., os.environ.get('III_BRIDGE_URL', 'ws://localhost:49134')) and pass that
variable into III(...), so the III constructor call uses the env-driven URL
instead of the literal string.
- Line 76: Replace the hardcoded WebSocket URL passed to III::new with the
environment-variable pattern used elsewhere: read the URI from an environment
variable (e.g., std::env::var("LANCE_WEBSOCKET_URI") or similar) and pass that
value into III::new (falling back or handling errors consistently with other
docs examples).
In `@docs/content/index.mdx`:
- Line 7: Edit the sentence "Today building a typical backend today means
connecting together many separate systems:" in docs/content/index.mdx: remove
the duplicated "today" and the redundant word "together" so it reads succinctly
(e.g., "Building a typical backend today means connecting many separate
systems:"); ensure punctuation and capitalization remain consistent with
surrounding text.
In `@docs/content/primitives-and-concepts/discovery.mdx`:
- Around line 3-13: Add a single framing sentence at the top of the section
clarifying that "Discovery" is a conceptual behavior of the system rather than a
core primitive; insert this immediately after the header/intro (before the
paragraph that begins "When a worker connects...") and word it succinctly like:
"Discovery is a system concept, not a primitive — unlike Function and Trigger,
it describes how the engine shares and updates function metadata across
workers." Ensure the sentence explicitly contrasts Discovery with the primitives
"Function" and "Trigger" so readers understand why this page is under Primitives
& Concepts.
In `@docs/content/primitives-and-concepts/index.mdx`:
- Line 8: Update the sentence that currently links only "primitives" (the text
"learning the
[primitives](/docs/primitives-and-concepts/functions-triggers-workers)") so the
link accurately reflects what it points to: either change the link text to
"primitives and concepts" if the target covers both, or split into two links
(e.g., "primitives" linking to
/docs/primitives-and-concepts/functions-triggers-workers and "Discovery" linking
to the Discovery page) so readers can navigate to both topics; edit the
displayed text and target URLs accordingly where the phrase "learning the
[primitives](/docs/primitives-and-concepts/functions-triggers-workers)" appears.
In `@docs/src/lib/components/ConfigReference.tsx`:
- Around line 176-180: The handleCopy function calls
navigator.clipboard.writeText which can reject; wrap the await call in a
try-catch inside handleCopy to prevent unhandled rejections, log or report the
error (e.g., console.error or showing a UI error) and only setCopied(true) when
the write succeeds; ensure setTimeout to reset copied still runs or is guarded
so state remains consistent on failure.
In `@docs/src/lib/config-parser.ts`:
- Around line 249-251: slugifyModuleName currently just lowercases and replaces
non-alphanumerics with hyphens which can produce empty strings or results
starting/ending with hyphens or digits; update slugifyModuleName to (1) collapse
multiple hyphens into a single '-', (2) trim leading and trailing hyphens, (3)
if the result is empty, return a safe default like 'module' or a deterministic
fallback, and (4) if the slug starts with a digit, prefix it (e.g., 'm-') so it
never begins with a number; locate and modify slugifyModuleName to apply these
steps.
In `@docs/src/lib/config-toc.ts`:
- Around line 31-33: The catch block in docs/src/lib/config-toc.ts currently
swallows errors and returns an empty array; update it to accept the caught error
(e.g., catch (err)) and log the error before returning ([]). Use the project's
logging mechanism if available (or console.error) and include contextual text
like "Failed to load config TOC:" plus the error to aid debugging; keep the
final behavior of returning an empty array unchanged.
In `@engine/README.md`:
- Line 23: The "Function" table entry is repetitive with three sentences all
starting "It"; update the Function description in the README table to
consolidate clauses and vary sentence structure—combine related actions into one
or two sentences (for example, merge "It receives input and optionally returns
output" with "It can exist anywhere..." and then list capabilities like mutating
state, invoking other functions, and modifying databases) so the entry reads
more fluidly while preserving all original information.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: dc3e779d-00a6-402b-b517-8730cc5930fe
⛔ Files ignored due to path filters (2)
engine/assets/banner.jpgis excluded by!**/*.jpgpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (50)
.cursor/rules/docs.mdc.cursor/skills/doc_workflow.mdREADME.mddocs/content/concepts/discovery.mdxdocs/content/concepts/function-and-trigger.mdxdocs/content/concepts/index.mdxdocs/content/concepts/meta.jsondocs/content/how-to/add-background-job.mdxdocs/content/how-to/configure-engine.mdxdocs/content/how-to/create-custom-trigger-type.mdxdocs/content/how-to/create-ephemeral-worker.mdxdocs/content/how-to/dead-letter-queues.mdxdocs/content/how-to/expose-http-endpoint.mdxdocs/content/how-to/iii-config.yamldocs/content/how-to/manage-state.mdxdocs/content/how-to/meta.jsondocs/content/how-to/queue-background-job.mdxdocs/content/how-to/react-to-state-changes.mdxdocs/content/how-to/schedule-cron-task.mdxdocs/content/how-to/stream-realtime-data.mdxdocs/content/how-to/use-functions-and-triggers.mdxdocs/content/how-to/use-queues.mdxdocs/content/how-to/use-trigger-conditions.mdxdocs/content/index.mdxdocs/content/meta.jsondocs/content/modules/module-exec.mdxdocs/content/primitives-and-concepts/discovery.mdxdocs/content/primitives-and-concepts/functions-triggers-workers.mdxdocs/content/primitives-and-concepts/index.mdxdocs/content/primitives-and-concepts/meta.jsondocs/content/tutorials/index.mdxdocs/content/tutorials/quickstart.mdxdocs/src/app/docs/[[...slug]]/page.tsxdocs/src/lib/components/ConfigReference.tsxdocs/src/lib/components/ConfigReferenceLoader.tsxdocs/src/lib/config-parser.tsdocs/src/lib/config-toc.tsdocs/src/mdx-components.tsxengine/README.mdsdk/README.mdsdk/packages/node/iii/README.mdsdk/packages/python/README.mdsdk/packages/python/iii/README.mdsdk/packages/rust/iii/README.mdwebsite/components/MachineView.tsxwebsite/components/Terminal.tsxwebsite/components/sections/AgentReadySection.tsxwebsite/components/sections/DependencyVisualization.tsxwebsite/components/sections/EngineSection.tsxwebsite/components/sections/HelloWorldSection.tsx
💤 Files with no reviewable changes (5)
- docs/content/concepts/meta.json
- docs/content/concepts/index.mdx
- docs/content/concepts/function-and-trigger.mdx
- sdk/packages/python/README.md
- docs/content/concepts/discovery.mdx
| - Unless instructed otherwise or writing edits for a specific language make sure to write code for all languages that iii has an sdk for and present it in `<Tabs>` with codeblocks. The `sdk/packages` folder indicates which languages are supported and how their respective SDKs work. | ||
| - Keep code functionally identical between languages. |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Docs/tooling files that may define MD/MDX behavior =="
fd -HI 'docusaurus\.config\..*|mint\.json$|astro\.config\..*|next\.config\..*|package\.json$|mdx-components\..*' . | sort || true
echo
echo "== Existing <Tabs> usage under docs/ (.md and .mdx) =="
rg -n --glob 'docs/**/*.md' --glob 'docs/**/*.mdx' '<Tabs|</Tabs>|@theme/Tabs' docs || true
echo
echo "== SDK package directories referenced by this rule =="
fd -td . . sdk/packages 2>/dev/null | sort || trueRepository: iii-hq/iii
Length of output: 30208
🏁 Script executed:
#!/bin/bash
# Check for plain .md files (not .mdx) in docs/
find docs/content -name "*.md" -not -name "*.mdx" 2>/dev/null | head -20
echo "---"
# Count them
find docs/content -name "*.md" -not -name "*.mdx" 2>/dev/null | wc -lRepository: iii-hq/iii
Length of output: 59
🏁 Script executed:
#!/bin/bash
# Check the docs next.config.mjs to understand how .md and .mdx are handled
cat -n docs/next.config.mjs | head -50Repository: iii-hq/iii
Length of output: 743
🏁 Script executed:
#!/bin/bash
# Check the actual rule in .cursor/rules/docs.mdc to see exact scope
cat -n .cursor/rules/docs.mdc | sed -n '1,50p'Repository: iii-hq/iii
Length of output: 3944
Narrow the multi-language <Tabs> rule to .mdx files only.
The rule currently targets docs/**/*.{md,mdx}, but <Tabs> is a JSX component that only works in MDX. While the repository currently has no plain .md files in docs/content/, the overly broad scope could mislead future contributors into attempting to use <Tabs> in a .md file where it would fail. Scope this rule to .mdx only.
The three supported SDKs (Node/TypeScript, Python, Rust) are consistently present across all existing examples, and there is no evidence of API parity gaps requiring selective language inclusion.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.cursor/rules/docs.mdc around lines 38 - 39, Update the docs rule that
currently targets the glob "docs/**/*.{md,mdx}" so it only matches MDX files by
changing the pattern to "docs/**/*.mdx"; this narrows enforcement to files where
the JSX <Tabs> component is valid and prevents suggesting <Tabs> usage in plain
.md files, while otherwise keeping the existing requirement to include all
supported SDKs (Node/TypeScript, Python, Rust) and keep examples functionally
identical across languages.
| ### Production | ||
|
|
||
| While iii's built-in `file_based` adapters can be used in production it's common to swap them out for other | ||
| adapters that are built for purpose such as Redis, or RabbitMQ. | ||
|
|
||
| <Callout title="Dont use in_memory in production" type="warn"> | ||
| Do not use in_memory storage in production. in_memory storage does not persist between engine restarts | ||
| if used can cause irrecoverable data loss. | ||
| </Callout> |
There was a problem hiding this comment.
Polish the production warning copy.
This block has a few visible copy issues (Don't, purpose-built, and the run-on sentence in the callout body). Since this is the page's main production warning, it should read a bit more cleanly before publish.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/content/how-to/configure-engine.mdx` around lines 68 - 76, Fix the copy
in the "Production" section and the Callout titled "Dont use in_memory in
production": change "Dont" to "Don't", replace "built for purpose" with
"purpose-built", and rewrite the Callout body into two clear sentences (e.g.,
"Do not use in_memory storage in production. in_memory storage does not persist
between engine restarts and can cause irrecoverable data loss.") — update the
Callout component and the surrounding paragraph text to use the corrected
wording and punctuation.
| description: 'Register a custom trigger type so functions can be fired by events that iii does not handle natively.' | ||
| --- | ||
|
|
||
| {/* TODO: Hold off until we have clarity from the devs on proper usecases. Then adjust and test. */} |
There was a problem hiding this comment.
Typo: "usecases" should be "use cases".
-{/* TODO: Hold off until we have clarity from the devs on proper usecases. Then adjust and test. */}
+{/* TODO: Hold off until we have clarity from the devs on proper use cases. Then adjust and test. */}📝 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.
| {/* TODO: Hold off until we have clarity from the devs on proper usecases. Then adjust and test. */} | |
| {/* TODO: Hold off until we have clarity from the devs on proper use cases. Then adjust and test. */} |
🧰 Tools
🪛 LanguageTool
[grammar] ~6-~6: Ensure spelling is correct
Context: ...we have clarity from the devs on proper usecases. Then adjust and test. */} ## Goal Cr...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/content/how-to/create-custom-trigger-type.mdx` at line 6, Update the
TODO comment that currently reads "proper usecases" to "proper use cases" so the
phrase is two words; locate the comment containing "{/* TODO: Hold off until we
have clarity from the devs on proper usecases. Then adjust and test. */}" and
change "usecases" to "use cases" in that string (keep the rest of the comment
unchanged).
| ```rust title="worker.rs" | ||
| use iii_sdk::{get_context, III}; | ||
| use serde_json::json; | ||
|
|
||
| #[tokio::main] | ||
| async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||
| let url = std::env::var("III_BRIDGE_URL").unwrap_or_else(|_| "ws://127.0.0.1:49134".to_string()); | ||
| let iii = III::new(&url); | ||
|
|
||
| iii.register_function("reports::generate", move |req| { | ||
| async move { | ||
| let ctx = get_context(); | ||
| let report_id = req["body"]["reportId"].as_str().unwrap_or("unknown"); | ||
|
|
||
| ctx.logger.info("Generating heavy report...", Some(json!({ "reportId": report_id }))); | ||
|
|
||
| // ... perform resource-intensive work here ... | ||
| tokio::time::sleep(std::time::Duration::from_secs(5)).await; // example 5 second delay | ||
|
|
||
| ctx.logger.info("Report generated", Some(json!({ "reportId": report_id }))); | ||
|
|
||
| Ok(json!({ | ||
| "status_code": 200, | ||
| "body": { "success": true, "reportId": report_id } | ||
| })) | ||
| } | ||
| }); | ||
| ``` | ||
| </Tab> |
There was a problem hiding this comment.
Incomplete Rust code block in Step 1.
The Rust example in Step 1 is missing the closing brace for the main() function. This makes the code block incomplete and potentially confusing for readers who might try to use it as-is.
The code should either:
- Include the full
main()function withiii.connect().await?;and closing braces, or - Clearly indicate it's a partial snippet that continues in Step 2
Since Step 2 continues the same main() function, consider adding a comment like // continued in Step 2... at the end.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/content/how-to/create-ephemeral-worker.mdx` around lines 68 - 96, The
Rust example's worker.rs snippet is missing the closing portion of the main()
function (unclosed braces) and the call to connect the III client, which makes
the block incomplete; fix by either completing main() in this snippet—after
registering the function call iii.connect().await? and then closing the async
main with the appropriate braces and Result return—or, if you intend to continue
in Step 2, add a clear inline note such as “// continued in Step 2...” at the
end of the iii.register_function block so readers know the snippet is
intentionally partial; reference the main() function,
iii.register_function("reports::generate", ...), and iii.connect().await? to
locate where to apply the change.
| {/* TODO: Check if this assertion on non-2xx status calls is correct | ||
| AND if there are any changes to allow for other statuses to pass (like 300 or user specified) */} | ||
|
|
There was a problem hiding this comment.
Remove TODO comments before publishing.
These TODO comments are visible in the rendered documentation and should be resolved or removed before merging.
-{/* TODO: Check if this assertion on non-2xx status calls is correct
-AND if there are any changes to allow for other statuses to pass (like 300 or user specified) */}
-
Register the payment API as an HTTP-invoked function.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/content/how-to/dead-letter-queues.mdx` around lines 15 - 17, Remove the
visible TODO comment block about the assertion on non-2xx status calls from the
documentation (the comment starting "TODO: Check if this assertion on non-2xx
status calls is correct...") before publishing; either delete it entirely or
replace it with a finalized explanation or resolved guidance that states whether
the assertion is correct and how to handle non-2xx/3xx statuses (or move any
remaining unresolved discussion into a contributor/developer note or issue
tracker link).
| <Callout title="Uncontrolled Endpoints" type="info"> | ||
| iii's Functions are not magic. While uncontrolled 3rd party HTTP endpoints can be represented as Functions they won't have | ||
| the same access to invokation, state, and databases as other Functions do. | ||
| the same access to invokation, state, and other engine functionality as other Functions do. |
There was a problem hiding this comment.
Typo: "invokation" should be "invocation".
-the same access to invokation, state, and other engine functionality as other Functions do.
+the same access to invocation, state, and other engine functionality as other Functions do.📝 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.
| the same access to invokation, state, and other engine functionality as other Functions do. | |
| the same access to invocation, state, and other engine functionality as other Functions do. |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/content/primitives-and-concepts/functions-triggers-workers.mdx` at line
23, Replace the misspelled word "invokation" with the correct spelling
"invocation" in the sentence that reads "the same access to invokation, state,
and other engine functionality as other Functions do." so it becomes "the same
access to invocation, state, and other engine functionality as other Functions
do."
| ## Ready to Dive In? | ||
|
|
||
| Head over to the [Functions & Triggers](/docs/how-to/use-functions-and-triggers) HOWTO and start building | ||
| a iii powered application; or visit the [Quickstart](/docs/tutorials/quickstart) and try out a working example. |
There was a problem hiding this comment.
Hyphenation: "iii powered" should be "iii-powered".
When used as a compound adjective before a noun, it should be hyphenated.
-Head over to the [Functions & Triggers](/docs/how-to/use-functions-and-triggers) HOWTO and start building
-a iii powered application; or visit the [Quickstart](/docs/tutorials/quickstart) and try out a working example.
+Head over to the [Functions & Triggers](/docs/how-to/use-functions-and-triggers) HOWTO and start building
+an iii-powered application; or visit the [Quickstart](/docs/tutorials/quickstart) and try out a working example.📝 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.
| a iii powered application; or visit the [Quickstart](/docs/tutorials/quickstart) and try out a working example. | |
| Head over to the [Functions & Triggers](/docs/how-to/use-functions-and-triggers) HOWTO and start building | |
| an iii-powered application; or visit the [Quickstart](/docs/tutorials/quickstart) and try out a working example. |
🧰 Tools
🪛 LanguageTool
[grammar] ~50-~50: Use a hyphen to join words.
Context: ...triggers) HOWTO and start building a iii powered application; or visit the [Quick...
(QB_NEW_EN_HYPHEN)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/content/primitives-and-concepts/functions-triggers-workers.mdx` at line
50, Replace the phrase "iii powered application" with the hyphenated compound
adjective "iii-powered application" in the content where the string "iii
powered" appears so the compound modifier is grammatically correct; search for
the exact token "iii powered" in the functions-triggers-workers.mdx content and
update it to "iii-powered".
| description: 'The core building blocks of iii-powered applications.' | ||
| --- | ||
|
|
||
| iii is built around three core concepts: **Function**, **Trigger**, and **Worker**. |
There was a problem hiding this comment.
Terminology inconsistency: "Worker" vs "Discovery" as core concept.
This line states the three core concepts are "Function, Trigger, and Worker." However, per project terminology, the three concepts should be "Function, Trigger, and Discovery" — with Discovery being the system capability for automatic registration/deregistration that distinguishes it from the primitives.
Consider whether this is an intentional terminology change or should align with the established definitions.
-iii is built around three core concepts: **Function**, **Trigger**, and **Worker**.
+iii is built around three core concepts: **Function**, **Trigger**, and **Discovery**.Alternatively, if Worker is now considered a core concept, the learning and other documentation should be updated for consistency.
Based on learnings: "Function, Trigger, and Discovery are the three concepts. Discovery is a concept but not a primitive—it's a system capability for automatic registration/deregistration."
📝 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 is built around three core concepts: **Function**, **Trigger**, and **Worker**. | |
| iii is built around three core concepts: **Function**, **Trigger**, and **Discovery**. |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/content/primitives-and-concepts/index.mdx` at line 6, The line that
lists core concepts currently reads "Function, Trigger, and Worker." Update this
wording to match project terminology by replacing "Worker" with "Discovery"
(i.e., make the three core concepts "Function, Trigger, and Discovery") or, if
the intent is that "Worker" is now a core concept, coordinate with the docs team
and update other references accordingly; locate the string "Function, Trigger,
and Worker" in the primitives-and-concepts content (index.mdx) and change it to
"Function, Trigger, and Discovery" to restore consistent terminology.
| python: `from iii import init, get_context | ||
|
|
||
| iii = III(os.environ.get("III_BRIDGE_URL", "ws://localhost:49134")) | ||
| await iii.connect() | ||
| iii = init(os.environ.get("III_BRIDGE_URL", "ws://localhost:49134")) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
head -300 website/components/sections/AgentReadySection.tsx | tail -230Repository: iii-hq/iii
Length of output: 8116
🏁 Script executed:
sed -n '70,80p' website/components/sections/AgentReadySection.tsx
sed -n '275,285p' website/components/sections/AgentReadySection.tsxRepository: iii-hq/iii
Length of output: 671
Add the missing os import in both Python snippets.
Both code examples use os.environ.get(...) without importing os. Lines 74–76 and 277–279 will cause NameError: name 'os' is not defined when users run the provided code.
Proposed fix
- python: `from iii import init, get_context
+ python: `import os
+from iii import init, get_context📝 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.
| python: `from iii import init, get_context | |
| iii = III(os.environ.get("III_BRIDGE_URL", "ws://localhost:49134")) | |
| await iii.connect() | |
| iii = init(os.environ.get("III_BRIDGE_URL", "ws://localhost:49134")) | |
| python: `import os | |
| from iii import init, get_context | |
| iii = init(os.environ.get("III_BRIDGE_URL", "ws://localhost:49134")) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@website/components/sections/AgentReadySection.tsx` around lines 74 - 76, The
Python examples in AgentReadySection.tsx call os.environ.get(...) but never
import os, causing a NameError; update both Python snippets that show "from iii
import init, get_context" and "iii = init(os.environ.get(...))" to include an
import os line at the top of each snippet so os.environ is defined.
| rust: `use iii_sdk::{init, InitOptions, get_context}; | ||
|
|
||
| let iii = III::new("ws://localhost:49134"); | ||
| iii.connect().await?; | ||
| let iii = init("ws://localhost:49134", InitOptions::default())?; | ||
| let logger = get_context().logger; | ||
| let tools = iii.list_functions().await?; | ||
|
|
||
| iii.register_function( | ||
| RegisterFunctionInput { id: "agent::research".into(), ..Default::default() }, | ||
| RegisterFunctionInput { id: "agent.research".into(), ..Default::default() }, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
fd -t f AgentReadySection.tsxRepository: iii-hq/iii
Length of output: 103
🏁 Script executed:
sed -n '85,105p' website/components/sections/AgentReadySection.tsxRepository: iii-hq/iii
Length of output: 1009
Add RegisterFunctionInput to the Rust example imports.
Line 98 constructs RegisterFunctionInput { ... }, but the import statement on line 91 does not include this type. The code example will not compile without it.
Proposed fix
- rust: `use iii_sdk::{init, InitOptions, get_context};
+ rust: `use iii_sdk::{get_context, init, InitOptions, RegisterFunctionInput};📝 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.
| rust: `use iii_sdk::{init, InitOptions, get_context}; | |
| let iii = III::new("ws://localhost:49134"); | |
| iii.connect().await?; | |
| let iii = init("ws://localhost:49134", InitOptions::default())?; | |
| let logger = get_context().logger; | |
| let tools = iii.list_functions().await?; | |
| iii.register_function( | |
| RegisterFunctionInput { id: "agent::research".into(), ..Default::default() }, | |
| RegisterFunctionInput { id: "agent.research".into(), ..Default::default() }, | |
| rust: `use iii_sdk::{get_context, init, InitOptions, RegisterFunctionInput}; | |
| let iii = init("ws://localhost:49134", InitOptions::default())?; | |
| let logger = get_context().logger; | |
| let tools = iii.list_functions().await?; | |
| iii.register_function( | |
| RegisterFunctionInput { id: "agent.research".into(), ..Default::default() }, |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@website/components/sections/AgentReadySection.tsx` around lines 91 - 98, The
Rust example is missing the RegisterFunctionInput import used when constructing
RegisterFunctionInput {...}; update the import list (which currently includes
init, InitOptions, get_context) to also import RegisterFunctionInput so the
example compiles; locate the import statement that references iii_sdk::{init,
InitOptions, get_context} and add RegisterFunctionInput to that brace-enclosed
list.
|
Can we use these cursor rules for docs outside the monorepo? It's not really needed in monorepo and will make the repo heavy later on. That's why I kept skills separate. Let me know what you think. You can also have symlink. |
Where should we store them instead? Also some doc-adjacent things will need to be covered too (ex. READMEs, jsdoc) Happy to store them outside as long as they're still automatically discovered by agents |
Summary by CodeRabbit
Release Notes
New Features
Documentation
Improvements