Codencer’s connector is the outbound-only bridge between a relay and one or more local Codencer daemons. It is not a planner, not an executor, and not a second orchestration brain.
If you want the full self-host operator sequence first, start with SELF_HOST_REFERENCE.md and return here for connector-specific semantics.
The connector is responsible for:
- persistent connector identity
- connector enrollment
- outbound authenticated websocket session to the relay
- explicit local instance sharing
- narrow proxying to the local daemon
The connector is not responsible for:
- planning
- direct local execution
- raw shell exposure
- generic tunneling
Default config path:
.codencer/connector/config.json
Status path:
.codencer/connector/status.json
The connector persists:
- relay URL and websocket metadata
- connector Ed25519 keypair
connector_idmachine_id- explicit shared-instance config
- the last local session snapshot in
status.json
The connector CLI now exposes the full local operator surface:
./bin/codencer-connectord enroll ...
./bin/codencer-connectord run ...
./bin/codencer-connectord status [--json]
./bin/codencer-connectord list [--json]
./bin/codencer-connectord discover [--json] [--root /path/to/repos]
./bin/codencer-connectord share --instance-id <id>
./bin/codencer-connectord share --daemon-url http://127.0.0.1:8085
./bin/codencer-connectord unshare --instance-id <id>
./bin/codencer-connectord config [--json] [--show-secrets]Command semantics:
statusreads the local status snapshot. Plain text is richer and includes configured shared/unshared instances.--jsonstill prints the raw status file for machine consumers.listshows every configured connector instance, includingshare: falseentries.discoverscans configureddiscovery_rootsplus any repeated--rootoverrides and reportsinstance_id,repo_root,manifest_path,daemon_url, and state asshared,known_unshared, ordiscovered_only. It never changes the allowlist.shareresolves the selector to a healthy local daemon before it persistsshare=true.--daemon-urlis the self-sufficient path.--instance-idworks only when discovery or existing connector metadata can resolve that instance back to a local daemon.unsharekeeps the entry but flipsshare=false. It does not delete history from the config.configprints the persisted config safely by default.private_keyis redacted unless--show-secretsis explicitly passed.--jsonis available for machine-readable output.
Use the local status file when you want to check connector state without contacting the relay:
./bin/codencer-connectord status --config .codencer/connector/config.json --jsonThe status file records:
connector_idmachine_idrelay_urlsession_statelast_connect_atlast_disconnect_atlast_heartbeat_atlast_errorshared_instances
Session states are intentionally small and honest:
disconnectedconnectingconnectederror
The plain-text status view additionally shows:
- currently shared instance IDs from the latest live session snapshot
- configured shared and unshared counts
- each configured instance selector line from the local allowlist
Preferred flow:
./bin/codencer-connectord enroll \
--relay-url http://127.0.0.1:8090 \
--daemon-url http://127.0.0.1:8085 \
--enrollment-token <token>Enrollment does two things:
- exchanges the one-time relay enrollment token for connector identity
- seeds one shared instance from the daemon URL used during enrollment
That enrollment seed is only a starting point. Use share, unshare, list, and discover for day-to-day instance management after the connector is enrolled.
The connector does not expose every discovered repo by default.
Sharing rules:
- discovery roots can discover manifests
- discovery alone does not share them
- the connector config is the allowlist
- only entries with
share: trueare advertised to the relay share: falseentries remain in the config so operators can see what has been intentionally withheld
Each shared instance entry can identify the local daemon by one or more of:
instance_iddaemon_urlmanifest_path
Practical note:
share --instance-idis only valid when that id is already discoverable from configured discovery roots or from existing connector metadata.share --daemon-urlis the canonical self-host operator path when you want the connector to prove the target daemon is live before advertising it.
Examples:
./bin/codencer-connectord share \
--config .codencer/connector/config.json \
--daemon-url http://127.0.0.1:8086
./bin/codencer-connectord unshare \
--config .codencer/connector/config.json \
--instance-id inst_repo_b
./bin/codencer-connectord list \
--config .codencer/connector/config.json
./bin/codencer-connectord discover \
--config .codencer/connector/config.json \
--root ~/srclist and discover are intentionally different:
listis the configured-state view from the local allowlist.discoveris the live visibility view from configured discovery roots plus optional overrides.discovernever auto-shares newly found instances.
At runtime the connector:
- fetches a relay challenge
- signs the challenge with its local private key
- opens an outbound websocket session
- advertises only shared instances
- reloads config before heartbeats and sends a fresh advertise when the effective shared set changes
- re-advertises after reconnect
No inbound listener is required for normal use.
Reconnect behavior is deliberately simple:
- failures back off exponentially from a short base delay up to a capped delay
- a successful connection resets the backoff window
- status snapshots keep the last error and latest heartbeat timestamps
The connector only proxies the narrow local Codencer API surface:
- instance read
- run create/list/read
- run patch operations such as abort
- run gate listing
- step submit
- step read
- step result
- step validations
- step artifact listing
- step logs
- step wait
- step retry
- gate read
- gate approve/reject
- artifact read
- artifact content read
The relay evidence path now works end to end for:
GET /api/v1/steps/{id}/validationsGET /api/v1/steps/{id}/artifactsGET /api/v1/steps/{id}/logs
It does not expose:
- raw shell
- arbitrary file reads
- generic network tunneling
Abort forwarding stays honest:
- the connector can forward an abort request
- it cannot guarantee a hard process kill on the local adapter side
- a remote abort is only considered successful when the daemon confirms the active step reached
cancelled
The default recommendation is:
- run the connector on the same side as the daemon
- keep the repo, worktrees, and artifacts on that same side
- let the relay be the remote surface
In mixed WSL/Windows setups:
- daemon and connector usually belong in WSL/Linux
- Antigravity broker and IDE may live on Windows
See WSL / Windows / Antigravity Topology for the practical topology.
To reset a connector locally:
- stop the connector process
- remove
.codencer/connector/config.json - enroll again with a fresh enrollment token
Relay-side disable and revocation are controlled by the relay control plane. The connector will report disconnect and auth failures honestly in status.json if the relay stops accepting the connector.