docs(prd): Indigo Matter Export — Indigo as a Matter bridge - #110
Conversation
Adds the draft PRD for a second, OUTBOUND role for indigo-matter: exporting a user-selected allow-list of Indigo devices as a Matter bridge, so Apple Home, Alexa, Google Home and SmartThings see them locally with no cloud relay and no per-ecosystem bridge plugin. Governed by workspace ADR-0006 (indigo-as-matter-bridge, accepted 2026-08-03): a plugin-owned matter.js bridge node running as a second Node process, with the inbound matter-server controller left untouched — the two share a Node runtime and nothing else. Default posture is inert: a fresh install exports nothing, pairs nothing, starts no bridge process. Status is Draft/scoping, with §10 open questions still outstanding — this records the design for review, it does not commit to the build. Split out of the handover PR (#109), where it was swept in by an over-broad `git add -A`. A feature spec deserves its own review rather than riding along inside a session record. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzVfnbsayjKCWQaYhD83qU
📝 WalkthroughWalkthroughChangesMatter export planning
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested reviewers: 🚥 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 |
# Conflicts: # indigo-matter.indigoPlugin/Contents/Info.plist
There was a problem hiding this comment.
Actionable comments posted: 15
🤖 Prompt for all review comments with 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.
Inline comments:
In `@docs/PRD-indigo-matter-export.md`:
- Around line 226-230: Update the “Configuration UI” export lifecycle
requirements to make the wholesale Export enable/disable control authoritative:
disabling it must remove export endpoints and stop the bridge regardless of
allow-list contents, while re-enabling must explicitly define whether previously
configured export entries are restored.
- Around line 220-221: Update the shutdown/reload behavior section in the PRD to
define fail-closed behavior while the plugin socket is unavailable: mark
endpoints unreachable, reject commands, avoid queuing non-idempotent commands,
and reconcile state after reconnect. Preserve the requirement that shutdown
closes the socket while leaving the agent running.
- Around line 16-19: The process/runtime description in the ADR-0006 bridge
section is contradictory. Update the plugin-owned bridge node description to
clarify that the two independent Node processes only use the same pinned
Node.js/toolchain version, share no runtime instance or state, and integrate
exclusively through the defined WebSocket protocol.
- Around line 198-199: Resolve the picker contract in the PRD so excluded
devices appear in a visible, non-selectable “Excluded” section with their reason
codes, rather than being absent or selectable. Update the conflicting
requirement near the excluded-device description and align it with the XAC9
requirement.
- Around line 218-219: Update the documented startup lifecycle so bridge-agent
management is controlled solely by export settings, not serverLocation or the
existing managed/ServerProcess path. Ensure a non-empty export allow-list
installs, starts, connects, and reconciles the bridge agent for both local and
remote matter-server configurations.
- Around line 11-14: Update the outbound Matter bridge summary to describe Apple
Home, Alexa, Google Home, and SmartThings as target ecosystems rather than
supported targets until the unresolved XOQ1/XOQ2 gates and XAC3 acceptance
criteria are satisfied; alternatively, add explicit per-ecosystem acceptance
criteria aligned with those validation gates.
- Around line 97-104: Expand the “Bridge node” storage requirements in section
4.3 to define owner-only permissions, secure secret storage, and atomic backup
snapshots. Specify that restoring bridge data must restore fabric credentials
together with the endpoint-ID allocation map as one consistent unit, preserving
pairings and XG4.
- Line 58: Update the fenced ASCII topology diagram in the PRD to specify the
text language by changing its opening fence to use text, resolving the MD040
markdownlint violation.
- Line 5: Update the Governing ADR link in PRD-indigo-matter-export.md to use
the repository-relative adr/0006-indigo-as-matter-bridge.md or
./adr/0006-indigo-as-matter-bridge.md path, removing the incorrect ../../
traversal.
- Around line 103-109: Update the PRD section around the Plugin and Endpoint
stability requirements to separate deterministic Bridged Device Basic
Information UniqueID derivation from endpoint ID allocation. Specify that
UniqueID values are encoded from the Indigo device ID, then document endpoint
allocation rules independently, including reserved endpoints, collision
handling, removal/re-add behavior, reset semantics, and cross-fabric
constraints; retain persistence and stability requirements for allocated
endpoint IDs.
- Around line 166-167: Expand the Lock and Water Valve role requirements in the
PRD table and referenced authorization section to define fail-safe
PIN/confirmation behavior: specify Matter responses for missing or invalid
credentials, credential storage and protection, retry/lockout handling, and that
Indigo actuation remains disabled until authorization succeeds. Ensure both
exported roles have explicit, consistent semantics rather than relying on the
existing cross-reference alone.
- Around line 213-214: Update the endpoint-capacity requirement in the PRD
before reconciliation: define the maximum supported bridged child count for the
pinned matter-server/matter.js version, replacing the “no hard cap” guidance.
Require allow-list changes exceeding that count to be rejected before endpoints
are added, while retaining warning behavior below the limit as appropriate.
- Around line 116-120: Expand the WebSocket bridge decision in the PRD to define
the bidirectional contract before E2, including message types, protocol
versioning, snapshot and revision semantics, acknowledgements, errors, ordering,
replay, deduplication, and backpressure. Specify the reconnect and
reconciliation behavior and keep the existing loopback binding and configurable
adjacent-port defaults.
- Around line 111-120: Update the Local protocol design to require
authentication for both bridge and client endpoints, not just loopback binding.
Specify an owner-only Unix socket with peer credential validation, or an
equivalent protected per-install capability, and require validation that the
connecting peer is an authorized managed peer before accepting Matter fabric
commands.
- Line 192: Update the sprinkler-device exclusion entry in the PRD to
acknowledge Matter’s Irrigation System (0x0040) and Water Valve (0x0042) types;
if the pinned matter-server/matter.js version does not support them, attribute
the exclusion to that library limitation rather than claiming Matter lacks an
irrigation-controller type. Ensure the v2 out-of-scope wording matches the
corrected rationale.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 7310bba2-e178-4cdd-be46-9e08520f19b8
📒 Files selected for processing (2)
docs/PRD-indigo-matter-export.mdindigo-matter.indigoPlugin/Contents/Info.plist
|
|
||
| **Status:** Draft — scoping | ||
| **Owner:** Simon | ||
| **Governing ADR:** [`../../docs/adr/0006-indigo-as-matter-bridge.md`](../../docs/adr/0006-indigo-as-matter-bridge.md) (accepted 2026-08-03) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Fix the governing ADR link.
From docs/PRD-indigo-matter-export.md, ../../docs/adr/... traverses above the repository's docs/ directory. Use adr/... or ./adr/....
Proposed link fix
-**Governing ADR:** [`../../docs/adr/0006-indigo-as-matter-bridge.md`](../../docs/adr/0006-indigo-as-matter-bridge.md)
+**Governing ADR:** [`adr/0006-indigo-as-matter-bridge.md`](adr/0006-indigo-as-matter-bridge.md)🤖 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/PRD-indigo-matter-export.md` at line 5, Update the Governing ADR link in
PRD-indigo-matter-export.md to use the repository-relative
adr/0006-indigo-as-matter-bridge.md or ./adr/0006-indigo-as-matter-bridge.md
path, removing the incorrect ../../ traversal.
| A second, outbound role for `indigo-matter`: export a user-selected set of | ||
| Indigo devices as a Matter **bridge**, so Apple Home, Alexa, Google Home and | ||
| SmartThings can see and control them locally, with no cloud relay and no | ||
| per-ecosystem bridge plugin. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Align ecosystem claims with the validation gates.
The summary names Apple Home, Alexa, Google Home, and SmartThings as supported targets. XOQ1 and XOQ2 remain unresolved, while XAC3 requires only Apple Home plus one non-Apple ecosystem. Mark these as target ecosystems until each one passes acceptance tests, or add per-ecosystem criteria.
🤖 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/PRD-indigo-matter-export.md` around lines 11 - 14, Update the outbound
Matter bridge summary to describe Apple Home, Alexa, Google Home, and
SmartThings as target ecosystems rather than supported targets until the
unresolved XOQ1/XOQ2 gates and XAC3 acceptance criteria are satisfied;
alternatively, add explicit per-ecosystem acceptance criteria aligned with those
validation gates.
| Per ADR-0006 this is a **plugin-owned matter.js bridge node** (a second Node | ||
| process, authored by us) plus an **explicit allow-list** (nothing is exported | ||
| until the user says so). The inbound controller (`matter-server`) is untouched; | ||
| the two processes share a Node runtime and nothing else. |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Clarify the process/runtime boundary.
A process cannot share a runtime instance with another process. This conflicts with “a second Node process” and “no shared state.” State whether both Node processes only share a pinned Node.js/toolchain version. Define the WebSocket protocol as the integration boundary.
🤖 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/PRD-indigo-matter-export.md` around lines 16 - 19, The process/runtime
description in the ADR-0006 bridge section is contradictory. Update the
plugin-owned bridge node description to clarify that the two independent Node
processes only use the same pinned Node.js/toolchain version, share no runtime
instance or state, and integrate exclusively through the defined WebSocket
protocol.
|
|
||
| ### 4.1 Process topology | ||
|
|
||
| ``` |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Add a language to the topology fence.
The supplied markdownlint-cli2 result reports MD040 at Line 58. Use text for this ASCII diagram.
Proposed fence fix
-```
+```text📝 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.
| ``` |
🧰 Tools
🪛 markdownlint-cli2 (0.23.1)
[warning] 58-58: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 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/PRD-indigo-matter-export.md` at line 58, Update the fenced ASCII
topology diagram in the PRD to specify the text language by changing its opening
fence to use text, resolving the MD040 markdownlint violation.
Source: Linters/SAST tools
| ### 4.3 Storage | ||
|
|
||
| - **Bridge node** — its own storage dir, sibling to the controller's: | ||
| `~/Library/Application Support/com.simons-plugins.indigo-matter/bridge-node/`. | ||
| Contains the node's operational credentials for each ecosystem fabric it has | ||
| joined, plus the endpoint-ID allocation map. | ||
| - **Plugin** — owns the allow-list and per-export metadata (role, name override, | ||
| polarity) in plugin prefs, backed up with Indigo's database. |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift
Define protection and restore semantics for fabric credentials.
The bridge storage contains operational credentials for every joined fabric. “Back it up” does not define owner-only permissions, secure secret storage, atomic snapshots, or joint restoration of credentials and the endpoint map. Specify these requirements before implementation to protect pairings and XG4.
🤖 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/PRD-indigo-matter-export.md` around lines 97 - 104, Expand the “Bridge
node” storage requirements in section 4.3 to define owner-only permissions,
secure secret storage, and atomic backup snapshots. Specify that restoring
bridge data must restore fabric credentials together with the endpoint-ID
allocation map as one consistent unit, preserving pairings and XG4.
| Excluded devices must be **absent from the picker with a reason shown**, not | ||
| silently missing. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Resolve the excluded-device picker contradiction.
These lines require excluded devices to be absent from the picker. XAC9 at Line 270 requires them to appear with reasons. Choose one contract. A visible, non-selectable “Excluded” section with reason codes satisfies both usability and safety.
🤖 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/PRD-indigo-matter-export.md` around lines 198 - 199, Resolve the picker
contract in the PRD so excluded devices appear in a visible, non-selectable
“Excluded” section with their reason codes, rather than being absent or
selectable. Update the conflicting requirement near the excluded-device
description and align it with the XAC9 requirement.
| - **Endpoint count:** no hard cap in v1, but log a warning past ~100 exports — | ||
| ecosystem per-home accessory limits (Apple's in particular) will bite first. |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Files matching PRD-indigo-matter-export:"
fd -a 'PRD-indigo-matter-export\.md|indigo.*matter|matter.*indigo' . | sed 's#^\./##' | head -100
echo
echo "Target lines:"
sed -n '180,240p' docs/PRD-indigo-matter-export.md 2>/dev/null || true
echo
echo "Search cap/capacity/reconcile/export endpoint mentions:"
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' \
'Endpoint count|max.*cap|capacity|reconcil|reject|allowed.*export|export count|matter\.js|endpoint' . | head -300Repository: simons-plugins/indigo-matter
Length of output: 38443
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Relevant file sizes:"
wc -l docs/PRD-indigo-matter-export.md indigo-matter.indigoPlugin/Contents/Server\ Plugin/matter_client.py 2>/dev/null || true
echo
echo "Import/version mentions:"
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' \
'matter-client|matter_client|matter-server|mjs|version|matter\.js|npm|yarn|requirements|dependencies' \
indigo-matter.indigoPlugin docs CLAUDE.md requirements.txt setup.py pyproject.toml package.json 2>/dev/null || true
echo
echo "matter_client outline:"
ast-grep outline 'indigo-matter.indigoPlugin/Contents/Server Plugin/matter_client.py' 2>/dev/null | sed -n '1,220p' || true
echo
echo "matter_client sync/reconcile/bridge sections:"
sed -n '1,320p' 'indigo-matter.indigoPlugin/Contents/Server Plugin/matter_client.py'Repository: simons-plugins/indigo-matter
Length of output: 50385
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "device_sync outline:"
ast-grep outline 'indigo-matter.indigoPlugin/Contents/Server Plugin/device_sync.py' 2>/dev/null | sed -n '1,260p' || true
echo
echo "device_sync relevant sync/reconcile sections:"
wc -l 'indigo-matter.indigoPlugin/Contents/Server Plugin/device_sync.py'
sed -n '1,360p' 'indigo-matter.indigoPlugin/Contents/Server Plugin/device_sync.py'Repository: simons-plugins/indigo-matter
Length of output: 18852
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "device_sync create/reconcile sections 360-720:"
sed -n '360,720p' 'indigo-matter.indigoPlugin/Contents/Server Plugin/device_sync.py'
echo
echo "search export allow-list/picker/capacity references:"
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' \
-i 'allow-list|allowlist|allow list|picker|selection|selections|endpoint count|max.*export|supported.*export|reconcile_all|endpoint_added|endpoint_removed|create_devices|delete_node' \
docs/PRD-indigo-matter-export.md indigo-matter.indigoPlugin/Contents/Server\ Plugin device_sync.py plugin.py | head -250Repository: simons-plugins/indigo-matter
Length of output: 31818
Define the supported bridge export capacity before reconciliation.
“No hard cap” plus a warning does not prevent an allow-list from exceeding matter-server endpoint, fabric, or runtime capacity. State the maximum exposed bridged child count for the pinned matter-server/matter.js version. Reject allow-list changes that exceed the supported count before adding endpoints.
🤖 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/PRD-indigo-matter-export.md` around lines 213 - 214, Update the
endpoint-capacity requirement in the PRD before reconciliation: define the
maximum supported bridged child count for the pinned matter-server/matter.js
version, replacing the “no hard cap” guidance. Require allow-list changes
exceeding that count to be rejected before endpoints are added, while retaining
warning behavior below the limit as appropriate.
| - `startup` — if the allow-list is non-empty, ensure the bridge agent is | ||
| installed and running; connect; reconcile endpoints against the allow-list. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Keep export lifecycle independent from serverLocation.
The existing startup() path derives managed from serverLocation and creates ServerProcess only for local mode. If bridge management reuses that condition, export will not start when the user runs a remote matter-server. Define a separate bridge manager keyed only to export settings.
As per the existing startup() path in indigo-matter.indigoPlugin/Contents/Server Plugin/plugin.py Lines 136-185, controller management is gated by serverLocation.
🤖 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/PRD-indigo-matter-export.md` around lines 218 - 219, Update the
documented startup lifecycle so bridge-agent management is controlled solely by
export settings, not serverLocation or the existing managed/ServerProcess path.
Ensure a non-empty export allow-list installs, starts, connects, and reconciles
the bridge agent for both local and remote matter-server configurations.
| - `shutdown` — close the socket; leave the agent running (PM-B rationale: | ||
| plugin reloads must not un-pair ecosystems). |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift
Define fail-closed behavior while the plugin socket is closed.
The bridge remains running during plugin reloads, but the PRD does not define its behavior while the Python plugin is unavailable. Mark endpoints unreachable, reject commands, avoid queuing non-idempotent commands, and reconcile after reconnect.
🤖 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/PRD-indigo-matter-export.md` around lines 220 - 221, Update the
shutdown/reload behavior section in the PRD to define fail-closed behavior while
the plugin socket is unavailable: mark endpoints unreachable, reject commands,
avoid queuing non-idempotent commands, and reconcile state after reconnect.
Preserve the requirement that shutdown closes the socket while leaving the agent
running.
| ### 5.5 Configuration UI | ||
|
|
||
| Plugin config gains an **Export** section: enable/disable export wholesale, | ||
| bridge-node port, and a pairing-status readout (which ecosystems are paired, | ||
| fabric slots used/remaining). Per-export settings live in the §5.1 dialog. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Make the wholesale Export switch authoritative.
The configuration adds an enable/disable control, but lifecycle rules only mention allow-list emptiness. Specify that disabling export removes endpoints and stops the bridge even when entries remain. Specify whether re-enabling restores those entries.
🤖 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/PRD-indigo-matter-export.md` around lines 226 - 230, Update the
“Configuration UI” export lifecycle requirements to make the wholesale Export
enable/disable control authoritative: disabling it must remove export endpoints
and stop the bridge regardless of allow-list contents, while re-enabling must
explicitly define whether previously configured export entries are restored.
Adds the draft PRD for a second, outbound role for
indigo-matter.Split out of #109, where it was swept in by an over-broad
git add -Aon my part. A feature spec deserves review on its own merits rather than riding along inside a session handover.What it proposes
Export a user-selected allow-list of Indigo devices as a Matter bridge, so Apple Home, Alexa, Google Home and SmartThings can see and control them locally — no cloud relay, no per-ecosystem bridge plugin.
Per workspace ADR-0006 (
indigo-as-matter-bridge, accepted 2026-08-03): a plugin-owned matter.js bridge node running as a second Node process. The inboundmatter-servercontroller is untouched — the two share a Node runtime and nothing else. The Python plugin never imports matter.js (ADR-0006 binding constraint).The substantive design is §5.2 (the Indigo → Matter mapping and its non-exportable set) and §5.1 (how a user picks devices). Most of the rest is lifecycle plumbing that closely mirrors what
server_process.pyalready does for the controller.Posture
Default is inert — a fresh install exports nothing, pairs nothing, and starts no bridge process (XG5). Nothing changes for existing users unless they opt in.
Status: Draft — scoping
This records the design for review; it does not commit to the build. §10 still carries open questions, and §9's milestones are unstarted. Merging this is agreeing the direction is worth writing down, not that it's ready to implement.
Verification
docs/PRD-indigo-matter-plugin.mdexists in-repo, and the governing ADR exists at the workspace pathdocs/adr/0006-indigo-as-matter-bridge.md. Note that ADR lives in the workspace repo, so the relative link resolves locally but not on GitHub — consistent with how other repos here reference workspace ADRs.Merge order
Version bumped to
2026.7.15, with #109 at2026.7.14. Merge #109 first so the versions land in order; if this one goes first, #109 will need a re-bump beforecheck-versionwill pass on a released tag.🤖 Generated with Claude Code
https://claude.ai/code/session_01BzVfnbsayjKCWQaYhD83qU
Summary by CodeRabbit
Documentation
Chores