I am trying to run a openclaw gateway on docker but having issues with approving my local device chat interface via the browser, since the CLI only gets operator.pairing scope which is not enough to approve the chat interface. I have to resort to HACKING the paired.json file in the same way it seems the CLI binary resolves it, by falling back to the local fallback trigger.
Is there no way for me to address this without having to resort to directly writing the paired.json file on the runtime directory?
=====
The compose exec approach does run the same CLI binary inside the container. The difference is what happens at the network layer before the CLI even gets to run the approve command.
Inside the container (compose exec):
CLI β ws://127.0.0.1:18789 β gateway sees 127.0.0.1 (loopback)
β isCliContainerLocalEquivalent() = true
β shouldAllowSilentLocalPairing() = true
β gateway silently auto-pairs the CLI with limited "operator.pairing" scopes
β connection SUCCEEDS (no error)
β CLI sends device.pair.approve RPC
β gateway rejects: "missing scope: operator.admin"
β this is NOT a "pairing required" error β no local fallback β hard failure
From the host (host-installed CLI):
CLI β ws://127.0.0.1:19789 β Docker NAT β gateway sees 172.17.0.1 (bridge IP)
β isCliContainerLocalEquivalent() = false (not loopback)
β shouldAllowSilentLocalPairing() = false
β gateway rejects: "device pairing required"
β this IS a "pairing required" error β local fallback triggers
β CLI writes device files directly with callerScopes: ["operator.admin"]
β success
The irony is that auto-pairing is a convenience feature β it lets CLI tools inside the container work without manual approval for routine operations. But it backfires for devices approve because the auto-paired CLI gets scopes that are too limited to approve other devices, and the error it gets ("missing scope") doesn't trigger the fallback path that would bypass it.