Canonical docs restructure — vendor Indigo 2025.2, fix fabricated facts (v2.0.0) - #46
Conversation
Indigo publishes an always-current, LLM-optimised canonical (llms.txt + llms-full.txt). Add tools/refresh_canonical.py to fetch the monolith, split it on its `--- Title (URL) ---` markers into small per-page Markdown files under reference/canonical/ (path mirrors the doc URL), build INDEX.md from the index, and stamp VERSION (indigo version + fetch date + sha256). Pinned to 2025.2; a `--check` mode diffs the live docs against the vendored copy to catch drift. This gives skills local, incremental, load-only-what-you-need reference that is canonical by construction — no per-fact webpage fetches, no fabrication. Vendors 68 pages (api/, plugin-dev/, scripting/) + INDEX.md + VERSION. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Arj5R66d73tc3PMPvHS65Z
…facts
Rewrite the api/dev skills and their commands to point at reference/canonical/
(relative to ${CLAUDE_PLUGIN_ROOT}) instead of hand-maintained derivatives, and
fix the pre-existing factual errors the canonical docs surfaced:
- API command envelope: `{"message": "indigo.<ns>.<cmd>", "objectId": id, ...}`
(was `{"name": "device.turnOn", "parameters": {"id": id}}` — wrong on every field)
- Drop non-existent `PUT /v2/api/indigo.devices/<id>` and fabricated `?detail=true`
- WebSocket: real per-feed URLs (7 feeds) + `refresh` message (was a fake subscribe)
- Auth: add HTTP Digest; reframe local secrets as a kind of API key; Authorizations portal
- super() story: emphasise deviceUpdated/deviceCreated/deviceDeleted (base does real
work) over deviceStartComm/StopComm (override hooks); note secure="true" only masks
- Stale dokuwiki 2025.1 links -> docs.indigodomo.com/2025.2
- Repoint html-pages command reference off the deleted device-commands.md
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Arj5R66d73tc3PMPvHS65Z
…25.2 The reference facts now live in reference/canonical/, so delete the 26 hand- maintained docs that duplicated (and in places fabricated) them: all of docs/api/, all of docs/plugin-dev/api/ (incl. iom/), and the concepts/ pages now covered by canonical (devices, actions, events, menu-items, configui, plugin-preferences, http-responder, scripting-shell). Keep the genuinely-additive on-ramps and correct them: - plugin-lifecycle.md: fix the super() contract (deviceCreated/Deleted/Updated need the base call; deviceStartComm/StopComm are optional override hooks) - quick-start.md: ServerApiVersion 3.0 -> 3.4 (first Python 3 + requirements.txt auto-install), example paths -> 2025.2, next-steps -> canonical - common-issues.md: paths -> 2025.2; soften "requirements.txt is the only path" (manual -t bundling is also supported) - README/reference/README: repoint to canonical; reframe the Python 2->3 guide as legacy-only; version sweep to 2025.2 / Python 3.13 / API 3.8 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Arj5R66d73tc3PMPvHS65Z
Major version: reference docs are now vendored canonical rather than hand-authored derivatives, and the skills route into them — a structural change to how the plugin sources its Indigo knowledge. Add the gap-analysis audit and the hybrid-restructure design under docs/plans/ for provenance. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Arj5R66d73tc3PMPvHS65Z
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (8)
📝 WalkthroughWalkthroughThis PR bumps plugin manifests to 2.0.0, vendors generated Indigo 2025.2 canonical documentation, removes duplicated reference pages, and rewrites command, plugin-development, API, installation, and troubleshooting guidance to use the canonical documentation layout. ChangesCanonical documentation migration
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ 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: 4
Note
Due to the large number of review comments, Critical severity comments were prioritized as inline comments.
🟠 Major comments (28)
docs/plans/2026-07-09-canonical-hybrid-restructure.md-58-69 (1)
58-69: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winEnsure refreshes remove obsolete generated pages.
generate()writes newly discovered sections but does not delete files that disappeared from the canonical source. After a page is removed or renamed, the documentedpython3 tools/refresh_canonical.pycommand leaves stale files behind, while--checkcontinues reporting drift. Generate into a clean directory or explicitly remove previously managed files before writing.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/plans/2026-07-09-canonical-hybrid-restructure.md` around lines 58 - 69, Ensure generate() removes obsolete generated pages before writing refreshed content. Generate into a clean temporary/output directory or track and delete previously managed files under reference/canonical/ while preserving unrelated files, so removed or renamed source sections cannot remain and --check accurately detects drift.reference/canonical/api/http.md-22-29 (1)
22-29: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winReconcile the auth guidance in
reference/canonical/api/http.md:23-29. The page says HTTP API requests “must be authenticated using an API Key,” butreference/canonical/api.mddocuments HTTP Digest, API keys, and local secrets as valid depending on server configuration. Update the canonical source so this page doesn’t exclude Digest/local-secret setups.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/api/http.md` around lines 22 - 29, Update the Authentication section in the HTTP API documentation to state that supported authentication methods depend on server configuration, including HTTP Digest, API keys, and local secrets, rather than requiring API keys universally. Retain the API-key usage and HTTPS security guidance, but clarify that the subsequent examples apply when API-key authentication is configured.reference/canonical/api/webhooks.md-175-180 (1)
175-180: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winGive the work GET trigger its own webhook ID.
Both triggers are assigned the ID
work-form, while the second URL uses/webhook/work-get. Requests to that URL will not match the documented trigger configuration.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/api/webhooks.md` around lines 175 - 180, The webhook trigger described as work-get incorrectly reuses the work-form webhook ID; update its webhook ID to work-get so it matches the documented /webhook/work-get URL while leaving the work-form trigger unchanged.commands/api.md-148-166 (1)
148-166: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winUse the canonical paths consistently in workflow instructions.
Because Line 22 defines paths relative to
${CLAUDE_PLUGIN_ROOT}, entries such asapi/websocket.mdandapi/messages.mdpoint to the wrong location. They should usereference/canonical/api/...just like the routing tables above.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@commands/api.md` around lines 148 - 166, Update the workflow instruction file references in the iOS/Android App, Web Dashboard, Automation Script, and Third-Party Integration sections to use the canonical `reference/canonical/api/...` paths, including websocket.md, http.md, messages.md, and webhooks.md, consistently with the routing tables.reference/canonical/api/rest-migration.md-61-64 (1)
61-64: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winDeclare the JSON content type in every HTTP curl example.
These commands send JSON bodies with
-dbut do not setContent-Type: application/json; curl therefore defaults to form encoding. Add the header to all HTTP examples.Proposed fix
-curl -X POST -H "Authorization: Bearer YOUR-API-KEY" -d '{"message":"indigo.device.turnOn","objectId":123456789}' http://127.0.0.1:8176/v2/api/command +curl -X POST -H "Authorization: Bearer YOUR-API-KEY" -H "Content-Type: application/json" -d '{"message":"indigo.device.turnOn","objectId":123456789}' http://127.0.0.1:8176/v2/api/commandAlso applies to: 76-80, 91-94, 111-118, 132-135, 156-166, 198-201, 249-252, 299-302
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/api/rest-migration.md` around lines 61 - 64, Update every HTTP curl example in the migration documentation, including the command near the REST API example and the additionally referenced examples, to add the `Content-Type: application/json` header alongside the existing authorization header whenever a JSON body is sent with `-d`.commands/api.md-139-145 (1)
139-145: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winDo not claim HTTP Digest works for both transports.
This section says both APIs accept HTTP Digest, but
reference/canonical/api/websocket.mdstates that WebSocket requests must use API-key authentication. Split the authentication guidance by transport so clients do not implement an unsupported WebSocket flow.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@commands/api.md` around lines 139 - 145, Update the Authentication section to distinguish HTTP and WebSocket transports: document HTTP Digest only for the HTTP API, and state that WebSocket requests require API-key authentication, while retaining the applicable local-secret and Bearer-token guidance. Remove the claim that both APIs accept HTTP Digest.reference/canonical/api/websocket.md-138-143 (1)
138-143: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winDo not JSON-encode the message twice.
msgis already serialized at Line 140, then serialized again at Line 142. The server receives a JSON string instead of a command object.- await ws.send(json.dumps(msg)) + await ws.send(msg)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/api/websocket.md` around lines 138 - 143, In the sender loop, avoid serializing the message twice: use the already serialized `msg` value created by `json.dumps(message)` when calling `ws.send`, so the server receives the command object rather than a JSON string.reference/canonical/plugin-dev.md-15-17 (1)
15-17: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winFix the canonical reference links.
These links target the pre-restructure
index.mdlayout, but the generated files areplugin-dev/reference/plugin-py.md,plugin-dev/reference/xml.md, andscripting.md. Update the canonical source or refresh-tool link rewriting, then regenerate the file.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/plugin-dev.md` around lines 15 - 17, Update the canonical reference links to target plugin-dev/reference/plugin-py.md, plugin-dev/reference/xml.md, and scripting.md, adjusting the canonical source or refresh-tool link rewriting as appropriate; then regenerate the documentation file.reference/canonical/scripting/iom-concepts.md-12-12 (1)
12-12: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winRemove stale pre-restructure links from the IOM reference.
The page still links to the old
index.mdhierarchy and removed derivative pages, including the SQL Logger and utility references. Update links to the generated canonical files or remove references to pages that are no longer vendored.Also applies to: 72-105, 241-241, 485-503
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/scripting/iom-concepts.md` at line 12, Update the IOM reference links throughout the affected sections, including the object-type list and ranges 72-105 and 485-503, to point to the generated canonical documentation files instead of the obsolete index.md hierarchy; remove links and references to deleted or no-longer-vendored derivative pages such as SQL Logger and utility references, including the item at 241.reference/canonical/scripting/guides/python-packages.md-171-174 (1)
171-174: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winDo not recommend global installation for Plugin dependencies.
For a Plugin, direct installation should target
Contents/Packages; globalsite-packagesis shared and can break unrelated Plugins or Indigo itself. Clarify this section as script-only guidance or provide the plugin-localpip3 -t .../Contents/Packages/command.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/scripting/guides/python-packages.md` around lines 171 - 174, The Python package guidance currently implies that plugin dependencies may be installed globally into site-packages. Revise the section around the pip3 installation guidance to clearly limit global installation to standalone scripts, and document that plugin dependencies must be installed into the plugin’s Contents/Packages directory using pip3’s target option.reference/canonical/scripting/guides/python-packages.md-6-17 (1)
6-17: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winMake the Python version consistent with Indigo 2025.2.
The page simultaneously documents Python 3.13 and Python 3.11, including hardcoded
3.11site-package paths and a “Python 3.11.6 Packages” heading. Update the stale version references and paths to the supported runtime, then regenerate the page.Also applies to: 72-79, 164-191
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/scripting/guides/python-packages.md` around lines 6 - 17, Update all stale Python 3.11 references in the guide, including prose, headings, site-package paths, and package listings, to consistently document the Python version supported by Indigo 2025.2 (Python 3.13). Review the sections around the package installation instructions and package tables, then regenerate the page after applying the changes.reference/canonical/plugin-dev/reference/plugin-py.md-18-19 (1)
18-19: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winFix the IOM reference link depth.
Use
../../scripting/iom-concepts.md#subscribing-to-object-change-events; the current../../../path resolves outsidereference/canonical/.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/plugin-dev/reference/plugin-py.md` around lines 18 - 19, Update the IOM reference link in the “Subscribing to Object Changes” note to use ../../scripting/iom-concepts.md#subscribing-to-object-change-events instead of the incorrect ../../../ path.reference/canonical/plugin-dev/guide.md-9-11 (1)
9-11: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winCorrect the relative scripting links.
From
reference/canonical/plugin-dev/guide.md, these targets need../../scripting/..., not../scripting/...; otherwise the links resolve under the nonexistentplugin-dev/scripting/directory.Also applies to: 112-112
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/plugin-dev/guide.md` around lines 9 - 11, Update the scripting documentation links in the plugin development guide, including the Indigo Object Model link, from ../scripting/... to ../../scripting/... so they resolve to the correct scripting directory.reference/canonical/scripting/iom-concepts.md-239-250 (1)
239-250: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winCorrect the
subscribeToChanges()spelling.The API name is case-sensitive. Change both occurrences of
subscribeTochanges()tosubscribeToChanges().🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/scripting/iom-concepts.md` around lines 239 - 250, Correct the case-sensitive method spelling in the “Object Events” table: update both occurrences of subscribeTochanges() to subscribeToChanges() for the heading and API references.reference/canonical/scripting/guides/python-packages.md-90-96 (1)
90-96: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winFix the package-install target path.
The command must target
Contents/Packages, not the singularContents/Package; otherwise the documented requirements installation will not populate the package directory used by IPH.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/scripting/guides/python-packages.md` around lines 90 - 96, The documentation’s pip installation target uses the incorrect singular Contents/Package path. Update the requirements installation step to consistently specify Contents/Packages, matching the success-log location and the directory consumed by IPH.reference/canonical/scripting.md-18-24 (1)
18-24: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winUpdate links to the flattened canonical paths.
This page still points at the removed
index.mdlayout, for examplereference/devices/index.md,reference/device-subclasses/index.md,../plugin-dev/index.md, and../api/index.md. Point these links at the generated.mdfiles or regenerate them through the refresh-tool mapping.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/scripting.md` around lines 18 - 24, Update the links in the scripting reference overview to use flattened canonical Markdown paths instead of removed index.md paths. Adjust the Devices, Device Subclasses, Plugin Development, and Integration APIs links, and verify all related references against the refresh-tool mapping.reference/canonical/plugin-dev/reference/dev-environment.md-282-286 (1)
282-286: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winCall
debugMode()in the example.The earlier example documents this as a method, but this code stores the bound method itself.
bool(debug_mode)will therefore be truthy regardless of the actual debugger state.-debug_mode = indigo.host.debugMode +debug_mode = indigo.host.debugMode()🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/plugin-dev/reference/dev-environment.md` around lines 282 - 286, Update the debug-mode example to invoke the `indigo.host.debugMode()` method before converting its returned integer to a boolean, ensuring `debug_mode_bool` reflects the actual debugger state rather than the bound method.reference/canonical/plugin-dev/reference/dev-environment.md-160-162 (1)
160-162: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winAvoid shell interpolation in the restart utility.
CFBundleIdentifieris external file data and is inserted directly intoos.system(...). Use argument-vector execution instead:import plistlib +import subprocess ... - os.system(f"/usr/local/indigo/indigo-restart-plugin -d -n {plist_dict['CFBundleIdentifier']}") + subprocess.run( + ["/usr/local/indigo/indigo-restart-plugin", "-d", "-n", + plist_dict["CFBundleIdentifier"]], + check=True, + )🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/plugin-dev/reference/dev-environment.md` around lines 160 - 162, The restart command currently interpolates the external CFBundleIdentifier value into os.system, creating shell-injection risk. Replace this invocation with argument-vector execution, such as subprocess.run or subprocess.call with a list of arguments, while preserving the existing utility flags and plist_dict['CFBundleIdentifier'] value.reference/canonical/plugin-dev/reference/plugin-py/general-methods.md-79-82 (1)
79-82: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winFix the destructor example’s
super()call.
super().__del__(self)passesselftwice becausesuper().__del__is already bound. The example should callsuper().__del__().🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/plugin-dev/reference/plugin-py/general-methods.md` around lines 79 - 82, Update the __del__ destructor example to call the bound superclass method as super().__del__() without passing self explicitly.reference/canonical/plugin-dev/reference/plugin-py/general-methods.md-203-205 (1)
203-205: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winPreserve the default sleep/wake lifecycle behavior.
These methods stop/start device communication and trigger processing by default. The guidance should tell overriding implementations to call
super().prepareToSleep()andsuper().wakeUp()unless they intentionally replace that behavior.Also applies to: 237-239
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/plugin-dev/reference/plugin-py/general-methods.md` around lines 203 - 205, Update the prepareToSleep() and wakeUp() guidance to state that overriding implementations should call super().prepareToSleep() and super().wakeUp() to preserve the default device communication and trigger-processing lifecycle, unless intentionally replacing that behavior.reference/canonical/plugin-dev/reference/plugin-py/device-methods.md-290-293 (1)
290-293: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winReturn a state ID, not a state value.
getDeviceDisplayStateId()must return the identifier of the state to display.dev.states['some_state_id']returns that state’s value; the example should return the key or select a key dynamically.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/plugin-dev/reference/plugin-py/device-methods.md` around lines 290 - 293, Update getDeviceDisplayStateId() to return the state identifier key, such as "some_state_id", rather than indexing dev.states and returning its value; if the identifier is dynamic, select and return the appropriate key from dev.states.reference/canonical/plugin-dev/reference/plugin-py/http-requests.md-5-14 (1)
5-14: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winDo not recommend sending API keys in query strings.
Query parameters are commonly logged and propagated, which can expose the bearer credential. Require the
Authorizationheader, or clearly document the query-string form as a legacy/insecure fallback with strict leakage warnings.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/plugin-dev/reference/plugin-py/http-requests.md` around lines 5 - 14, The HTTP authentication guidance in the plugin request documentation permits insecure API-key query parameters. Update the authentication section to require the Authorization header as the recommended and supported method, and remove the query-string example or explicitly label it as a legacy insecure fallback with prominent warnings about logging and credential leakage.reference/canonical/plugin-dev/reference/plugin-py/device-methods.md-297-305 (1)
297-305: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winUse the actual method name in the guidance.
The prose names
get_device_state_list(), but the API method isgetDeviceStateList(). Users copying the prose would define a method Indigo never calls.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/plugin-dev/reference/plugin-py/device-methods.md` around lines 297 - 305, Replace the prose references to get_device_state_list() with the actual API method name getDeviceStateList(), including the subclassing guidance, so users implement the method the server invokes.reference/canonical/plugin-dev/reference/plugin-py/trigger-methods.md-36-44 (1)
36-44: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winInvert the property-change comparison.
The example currently returns
Truewhen the values are equal, despite the description saying it should identify changed properties. Correct the generated source:def didTriggerProcessingPropertyChange(self, origTrigger, newTrigger): - some_property_changed = (origTrigger['some_prop'] == newTrigger['some_prop']) + some_property_changed = (origTrigger['some_prop'] != newTrigger['some_prop'])Otherwise trigger processing can restart for unchanged configuration and fail to restart after a real change.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/plugin-dev/reference/plugin-py/trigger-methods.md` around lines 36 - 44, Correct didTriggerProcessingPropertyChange so some_property_changed is true only when origTrigger['some_prop'] and newTrigger['some_prop'] differ; preserve the existing boolean return behavior so processing restarts only after an actual property change.reference/canonical/scripting/reference/device-subclasses/multiio.md-34-35 (1)
34-35: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winCorrect the
sensorInputsAlltype description.This row describes sensor input values as binary values and booleans, contradicting the preceding
sensorInputsandsensorInput#definitions, which correctly identify them as integers.-| <span class="nw cb">`sensorInputsAll`</span> | string | N/A | a comma separated list of all binary input values. Can be accessed as a Python list of booleans by using `dev.sensorInputs`. | +| <span class="nw cb">`sensorInputsAll`</span> | string | N/A | a comma-separated list of all sensor input values. Can be accessed as a Python list of integers by using `dev.sensorInputs`. |🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/scripting/reference/device-subclasses/multiio.md` around lines 34 - 35, Update the sensorInputsAll entry in the multi-I/O device property table so its description consistently identifies the comma-separated values as integers, removing references to binary values and booleans while preserving the sensorInputs access detail as appropriate.reference/canonical/scripting/reference/device-subclasses/speedcontrol.md-69-77 (1)
69-77: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winFix the Set Speed Index example.
Line 77 calls
increaseSpeedIndexeven though this section documentssetSpeedIndex. Users copying the example will execute a different command than intended.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/scripting/reference/device-subclasses/speedcontrol.md` around lines 69 - 77, Update the second command example in the “Set Speed Index” section to call indigo.speedcontrol.setSpeedIndex instead of increaseSpeedIndex, while preserving its intended arguments.reference/canonical/scripting/reference/device-subclasses/speedcontrol.md-23-23 (1)
23-23: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winChange
speedIndexstate type to integer.The class property at Line 12 and the speed-index commands define this value as an integer, but the state table says boolean. Correct the canonical source and regenerate.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/scripting/reference/device-subclasses/speedcontrol.md` at line 23, Update the speedIndex state type from boolean to integer in the canonical source, ensuring it matches the class property and speed-index command definitions; then regenerate the derived documentation.reference/canonical/plugin-dev/reference/xml/devices.md-64-71 (1)
64-71: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winUse the documented
indigo.device.createsignatureThis example passes
indigo.kRelayDeviceSubType.Pluginas the first positional argument and omitsprotocolandname, so it doesn’t match the documented call shape shown later.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/plugin-dev/reference/xml/devices.md` around lines 64 - 71, Update the example using indigo.device.create to match its documented signature: pass the device name and protocol explicitly, and use indigo.kRelayDeviceSubType.Plugin in the appropriate subtype argument rather than as the first positional argument. Keep the subsequent model, subModel, and name assignments consistent with the creation call.
🧹 Nitpick comments (2)
reference/canonical/plugin-dev.md (1)
9-11: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse
Plugincapitalization for Indigo components.Use lowercase only for identifiers such as
plugin.py; prose referring to Indigo tools should usePlugin.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/plugin-dev.md` around lines 9 - 11, Update the prose in the canonical plugin developer guide to capitalize Indigo component references as “Plugin,” including “Plugin Developer’s Guide,” “Plugin Host,” and “Plugin callbacks,” while keeping lowercase only for identifiers such as plugin.py.Source: Coding guidelines
reference/canonical/plugin-dev/reference/plugin-py/logging.md (1)
21-26: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse
warning()instead of deprecatedwarn().The example should demonstrate the supported logging API:
-self.logger.warn(u"Warning log message") +self.logger.warning(u"Warning log message")Please verify the generated source against the Python logging API before regenerating.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@reference/canonical/plugin-dev/reference/plugin-py/logging.md` around lines 21 - 26, Replace the deprecated self.logger.warn() example with self.logger.warning() in the logging API example, then verify the generated source uses the supported Python logging method before regenerating.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 5e50d57a-9c98-41ea-abe5-61b838217383
📒 Files selected for processing (115)
.claude-plugin/marketplace.json.claude-plugin/plugin.jsonREADME.mdcommands/api.mdcommands/dev.mdcommands/html-pages.mddocs/api/README.mddocs/api/authentication.mddocs/api/device-commands.mddocs/api/http-api.mddocs/api/overview.mddocs/api/websocket-api.mddocs/plans/2026-07-09-canonical-docs-audit.mddocs/plans/2026-07-09-canonical-hybrid-restructure.mddocs/plugin-dev/README.mddocs/plugin-dev/api/README.mddocs/plugin-dev/api/indigo-object-model.mddocs/plugin-dev/api/iom/architecture.mddocs/plugin-dev/api/iom/command-namespaces.mddocs/plugin-dev/api/iom/constants.mddocs/plugin-dev/api/iom/containers.mddocs/plugin-dev/api/iom/devices.mddocs/plugin-dev/api/iom/filters.mddocs/plugin-dev/api/iom/subscriptions.mddocs/plugin-dev/api/iom/triggers.mddocs/plugin-dev/api/iom/utilities.mddocs/plugin-dev/concepts/README.mddocs/plugin-dev/concepts/actions.mddocs/plugin-dev/concepts/configui.mddocs/plugin-dev/concepts/devices.mddocs/plugin-dev/concepts/events.mddocs/plugin-dev/concepts/http-responder.mddocs/plugin-dev/concepts/menu-items.mddocs/plugin-dev/concepts/plugin-lifecycle.mddocs/plugin-dev/concepts/plugin-preferences.mddocs/plugin-dev/concepts/scripting-shell.mddocs/plugin-dev/patterns/testing.mddocs/plugin-dev/quick-start.mddocs/plugin-dev/troubleshooting/common-issues.mdreference/README.mdreference/canonical/INDEX.mdreference/canonical/VERSIONreference/canonical/api.mdreference/canonical/api/http.mdreference/canonical/api/messages.mdreference/canonical/api/rest-migration.mdreference/canonical/api/webhooks.mdreference/canonical/api/websocket.mdreference/canonical/plugin-dev.mdreference/canonical/plugin-dev/guide.mdreference/canonical/plugin-dev/reference/dev-environment.mdreference/canonical/plugin-dev/reference/plugin-py.mdreference/canonical/plugin-dev/reference/plugin-py/additional-topics.mdreference/canonical/plugin-dev/reference/plugin-py/device-methods.mdreference/canonical/plugin-dev/reference/plugin-py/general-methods.mdreference/canonical/plugin-dev/reference/plugin-py/helper-methods.mdreference/canonical/plugin-dev/reference/plugin-py/http-requests.mdreference/canonical/plugin-dev/reference/plugin-py/logging.mdreference/canonical/plugin-dev/reference/plugin-py/message-flow.mdreference/canonical/plugin-dev/reference/plugin-py/properties.mdreference/canonical/plugin-dev/reference/plugin-py/trigger-methods.mdreference/canonical/plugin-dev/reference/plugin-py/variable-methods.mdreference/canonical/plugin-dev/reference/xml.mdreference/canonical/plugin-dev/reference/xml/actions.mdreference/canonical/plugin-dev/reference/xml/configui.mdreference/canonical/plugin-dev/reference/xml/configui/button.mdreference/canonical/plugin-dev/reference/xml/configui/checkbox.mdreference/canonical/plugin-dev/reference/xml/configui/color-picker.mdreference/canonical/plugin-dev/reference/xml/configui/dialog-close.mdreference/canonical/plugin-dev/reference/xml/configui/dynamic-lists.mdreference/canonical/plugin-dev/reference/xml/configui/label.mdreference/canonical/plugin-dev/reference/xml/configui/list.mdreference/canonical/plugin-dev/reference/xml/configui/popup-menu.mdreference/canonical/plugin-dev/reference/xml/configui/separator.mdreference/canonical/plugin-dev/reference/xml/configui/serial-port.mdreference/canonical/plugin-dev/reference/xml/configui/text-field.mdreference/canonical/plugin-dev/reference/xml/configui/validation.mdreference/canonical/plugin-dev/reference/xml/devices.mdreference/canonical/plugin-dev/reference/xml/events.mdreference/canonical/plugin-dev/reference/xml/menuitems.mdreference/canonical/plugin-dev/reference/xml/pluginconfig.mdreference/canonical/plugin-dev/reference/xml/supporturl.mdreference/canonical/plugin-dev/sdk-examples.mdreference/canonical/plugin-dev/tutorials/building.mdreference/canonical/scripting.mdreference/canonical/scripting/guides/python-packages.mdreference/canonical/scripting/iom-concepts.mdreference/canonical/scripting/reference/action-groups.mdreference/canonical/scripting/reference/actions.mdreference/canonical/scripting/reference/device-subclasses.mdreference/canonical/scripting/reference/device-subclasses/dimmer.mdreference/canonical/scripting/reference/device-subclasses/multiio.mdreference/canonical/scripting/reference/device-subclasses/relay.mdreference/canonical/scripting/reference/device-subclasses/sensor.mdreference/canonical/scripting/reference/device-subclasses/speedcontrol.mdreference/canonical/scripting/reference/device-subclasses/sprinkler.mdreference/canonical/scripting/reference/device-subclasses/thermostat.mdreference/canonical/scripting/reference/devices.mdreference/canonical/scripting/reference/devices/base-class.mdreference/canonical/scripting/reference/devices/dictionary.mdreference/canonical/scripting/reference/event-data-paths.mdreference/canonical/scripting/reference/folders.mdreference/canonical/scripting/reference/insteon-commands.mdreference/canonical/scripting/reference/schedules.mdreference/canonical/scripting/reference/server-commands.mdreference/canonical/scripting/reference/triggers.mdreference/canonical/scripting/reference/utils.mdreference/canonical/scripting/reference/variables.mdreference/canonical/scripting/reference/x10-commands.mdreference/canonical/scripting/tutorial.mdskills/api/SKILL.mdskills/dev/SKILL.mdskills/html-pages/SKILL.mdskills/html-pages/references/indigo-api-js.mdtools/refresh_canonical.py
💤 Files with no reviewable changes (26)
- docs/api/overview.md
- docs/plugin-dev/concepts/scripting-shell.md
- docs/plugin-dev/api/iom/command-namespaces.md
- docs/plugin-dev/concepts/menu-items.md
- docs/plugin-dev/concepts/actions.md
- docs/plugin-dev/api/iom/devices.md
- docs/plugin-dev/api/iom/triggers.md
- docs/plugin-dev/concepts/devices.md
- docs/plugin-dev/concepts/http-responder.md
- docs/plugin-dev/api/iom/containers.md
- docs/plugin-dev/api/README.md
- docs/plugin-dev/api/iom/subscriptions.md
- docs/plugin-dev/api/indigo-object-model.md
- docs/plugin-dev/api/iom/architecture.md
- docs/plugin-dev/api/iom/constants.md
- docs/plugin-dev/concepts/configui.md
- docs/api/http-api.md
- docs/api/authentication.md
- docs/plugin-dev/api/iom/filters.md
- docs/plugin-dev/concepts/events.md
- docs/plugin-dev/concepts/README.md
- docs/api/websocket-api.md
- docs/api/README.md
- docs/plugin-dev/concepts/plugin-preferences.md
- docs/plugin-dev/api/iom/utilities.md
- docs/api/device-commands.md
| ```xml | ||
| <Device type="sensor" subType="kSensorDeviceSubType.Temperature, ui=Outdoor Temperature" id="my_temp_sensor", allowUserCreation="false"> | ||
| ``` |
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
Fix the malformed XML attribute syntax.
The comma after id="my_temp_sensor" makes this snippet invalid XML. Remove it before publishing the example.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@reference/canonical/plugin-dev/reference/xml/devices.md` around lines 80 -
82, Remove the comma after the id attribute in the Device XML example so the
opening tag is valid XML, preserving the existing attributes and values.
| ```python | ||
| def turnOffLight(self, valuesDict, typeId): | ||
| indigo.server.log(f"Turning off light: {valuesDict["targetDevice"]}") | ||
| # perform the action here. If there are errors in any of the fields then | ||
| # you can return (False, valuesDict, errorsDict) just like a validation | ||
| # method and the dialog won't close and will show the errors. If you | ||
| # return True then the dialog will close when the method completes. | ||
| errorsDict = indigo.Dict() | ||
| return (True, valuesDict, errorsDict) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
Fix the invalid f-string in the copy-paste example.
The outer and inner strings both use double quotes:
indigo.server.log(f"Turning off light: {valuesDict["targetDevice"]}")Use single quotes for the dictionary key or the outer string.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@reference/canonical/plugin-dev/reference/xml/menuitems.md` around lines 69 -
77, Fix the invalid f-string in the turnOffLight example by changing either the
valuesDict key quotes or the outer f-string quotes so the delimiters do not
conflict; preserve the existing log message and behavior.
| ```xml | ||
| <?xml version="1.0"?> | ||
| <Events> | ||
| <SupportURL>http://www.yourdomain.com/plugin/pluginEvents.html</SupportURL> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
Move the XML declaration to the first character.
Leading spaces before <?xml version="1.0"?> can make the copied XML document invalid because the declaration must appear at the beginning.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@reference/canonical/plugin-dev/tutorials/building.md` around lines 161 - 164,
Remove the leading whitespace before the XML declaration in the Events example
so <?xml version="1.0"?> is the document’s first characters, before the Events
element.
| ```python | ||
| def deviceCreated(self, dev): | ||
| # Receives a copy of the device instance | ||
| self.logger.debug(f"{dev.name} created." | ||
| ``` | ||
| ```python | ||
| def deviceDeleted(self, dev): | ||
| # Receives a copy of the device instance | ||
| self.logger.info(f"{dev.name} deleted." | ||
| ``` |
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
Close both logger calls in the device callback examples.
The deviceCreated and deviceDeleted snippets are missing a closing ), so neither example is valid Python.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@reference/canonical/plugin-dev/tutorials/building.md` around lines 233 - 242,
Fix the `deviceCreated` and `deviceDeleted` callback examples by adding the
missing closing parenthesis to each `self.logger.debug` and `self.logger.info`
call, respectively, so both snippets are valid Python.
Reconcile with PR #41 (merged after this branch started), which added undocumented Indigo field knowledge to four concepts/ files this branch had deleted. Keep those files (they hold non-canonical gotchas — state-ID naming rules, uiPath crash, dynamic-state cache corruption, cross-plugin executeAction, deviceUpdated loop guard, custom-event method traps, pluginProps underscore rule); they are thinned to field-notes in the following commit. Keep version 2.0.0 over main's 1.9.5; common-issues.md auto-merged (both changes retained). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Arj5R66d73tc3PMPvHS65Z
…dev skill The 4 concept files re-added by the #41 merge each mixed canonical-duplicating narrative with genuinely undocumented field knowledge. Strip the narrative (now in reference/canonical/) and keep only the field notes: - devices.md: state-ID naming rules, reserved-name shadowing, dynamic getDeviceStateList live-cache trap, deviceUpdated self-loop guard - actions.md: uiPath PascalCase (client crash), cross-plugin executeAction - events.md: fireEvent/triggerEvent don't exist -> trigger.execute pattern - plugin-preferences.md: pluginPrefs vs pluginProps '_' prefix rule Fix their See-Also links (were pointing at deleted files) to canonical, and surface the field notes prominently from skills/dev/SKILL.md + commands/dev.md. The State-ID heading anchor is preserved (common-issues.md links to it). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Arj5R66d73tc3PMPvHS65Z
…om/ files) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Arj5R66d73tc3PMPvHS65Z
Why
Indigo completely rewrote their documentation (now published as a machine-readable
llms.txt+llms-full.txt) but did not change functionality. A 4-domain audit against the new canonical found our ~11k lines of hand-maintained derivative docs had drifted and fabricated specifics that never existed. Rather than keep hand-patching a parallel corpus, this vendors the canonical and reshapes the skills to route into it.What
Vendoring engine (P1) —
tools/refresh_canonical.py(stdlib-only) fetches the monolith, splits it on its--- Title (URL) ---markers into 68 small per-page files underreference/canonical/**(path mirrors the doc URL), buildsINDEX.md, and stampsVERSION. Pinned to 2025.2;--checkmode catches drift. Skills now do local, incremental, load-only-what-you-need discovery — canonical by construction.Routing rewrites + correctness (P2) —
api/devskills + commands now route intoreference/canonical/(anchored to${CLAUDE_PLUGIN_ROOT}), with the pre-existing HIGH-severity errors fixed:{"message":"indigo.<ns>.<cmd>","objectId":id,…}(wasname/parameters.id— wrong on every field)PUT /v2/api/indigo.devices/<id>and fabricated?detail=truerefreshmessage (was a fake subscribe)super()contract corrected (emphasis on deviceUpdated/Created/Deleted);secure="true"only masks, not stored securelyPrune + thin (P3) — deleted 26 duplicated/fabricated docs; kept & corrected the on-ramps (
quick-start,plugin-lifecycle);ServerApiVersion 3.0 → 3.4; version sweep to 2025.2 / Python 3.13 / API 3.8; reframed the Python 2→3 guide as legacy-only.Tier-3 coverage gaps (webhooks,
ValidationError,subTypeenums, symlink dev workflow, debuggers) close for free — they're now canonical pages the skills route into.Notes for review
reference/canonical/**is generated — never hand-edit; re-runtools/refresh_canonical.py.docs/plans/2026-07-09-canonical-docs-audit.mdand…-hybrid-restructure.md.🤖 Generated with Claude Code
https://claude.ai/code/session_01Arj5R66d73tc3PMPvHS65Z
Summary by CodeRabbit
New Features
Documentation
Chores