Skip to content

Adapters ​

app/src/adapters/ is I/O. Adapters may import ports, domain, shared, and other adapters. They must not import presentation/ or application/ (bootstrap injects commands).

This page is a catalog of every adapter package. Read the named files; do not treat Supervisor as the only place behavior lives.

adapters/daemon/ — supervisor host ​

The daemon is split so supervisor.ts coordinates rather than implementing every subsystem inline.

FileRole
supervisor.tsLock, run(), dispatch(), runtime maps, lifecycleSession(), persist, bind orchestrator
daemon.tsresolveDaemonTarget / state-dir scan (client-side helper living next to daemon concepts)
recover.tsAdopt PIDs/containers from state.json
reload.tsConfig + plugin reload, watchConfig, diffReload, registry apply
service-watch.tsPer-service file watchers → restart
environment-bridge.tsBuilds EnvRequest (ports, proxy URL, token endpoint, OTLP, recipes) for resolveEnvironment
identity-coordinator.tsIdentity cache, credential list, SA probes, refreshIdentity
proxy-coordinator.tsHTTP/gRPC proxy + token endpoint bind; suppression flag; applyConfig hot-swaps routes when listen is unchanged
mcp-coordinator.tsMCP listen, token rotate, deny-list persistence
web-coordinator.tsLoopback web UI listen
telemetry-coordinator.tsOptional OTLP HTTP receiver
resource-sampler.tsHost CPU/memory samples for Stats
snapshot.tsStatusSnapshot assembly + formatStatusFromSnapshot

Supervisor still owns persistence, adoption orchestration, and the facades (asMcpHost()). Public start/stop/restart delegate to the orchestrator.

adapters/rpc/ ​

FileRole
server.tsListen, auth, dispatch, event subscribe, write queue
controller.tsDial, spawn _supervisor, Controller, handshake
params.tsLoose JSON → domain filters/arrays

See RPC.

adapters/config/ ​

See config pipeline. Entry barrel: index.ts (re-exports domain config types for adapter convenience — presentation must still not import this barrel).

adapters/process/ ​

FileRole
processes.tsProcessManager implements ProcessRuntime; spawn via Bun.spawn; adopt; runOnce; delegates containers
peer-caller.tsMap a loopback TCP peer to a managed service for LLM and traffic caller attribution. Linux: socket inode from the kernel (sock-diag.ts), else from shared reads of /proc/net/tcp[6], then the fds of managed processes and their descendants. Processes devctl does not run that held recently looked-up sockets ("hot owners", found by a search that runs beside the managed scan) join that scan in size order after their last descriptor is checked, and a holder is judged fresh against the services. Fd directories are listed only when their turn comes, and a scan stops as soon as the kernel reports the socket closed. Elsewhere: lsof/netstat owner pid, parent walk, pgid
sock-diag.tsAsk the kernel for one TCP socket by both ends: a netlink NETLINK_SOCK_DIAG exact-match request through bun:ffi to glibc, non-blocking. Linux only
unix.tsProcess inspect, tree kill, vm_stat samples, command matching
windows.tsSame for Windows (WMIC/CIM, named-pipe world)

Host processes are detached on Unix so they survive the client. Graceful stop: SIGTERM then SIGKILL after graceMs.

adapters/containers/ ​

Docker/Podman: startContainer, adoptContainer, port publishes, env (no full process layer), limits from domain/service/container-limits.ts. Integration tests gated on DEVCTL_CONTAINER_TESTS=1.

adapters/environment/ ​

resolveEnvironment, ENV_SOURCE_ORDER, dotenv family, always-on secrets_env (.devctl/secrets.env then ~/.devctl/secrets.env), keychain/secret-manager fetch, an in-memory sops decrypt (sops --decrypt at daemon start and reload; plaintext is not written), and literal env values from a service's Terraform (environment.terraform). ${} resolution via config/refs.ts (Terraform literals are not expanded). Plugin EnvironmentSource spliced before defaults. Documented for users in docs/environment.md; this adapter is the implementation.

adapters/health/ ​

Built-in checkers: http, tcp, process, command, grpc (grpc.health.v1.Health/Check over h2c/h2). healthCheckerFactory(plugins) looks up type. Unknown types fail validation after plugins load.

adapters/google/ ​

FileRole
google.tsdetectGoogle, loginGoogle, logoutGoogle (gcloud / ADC)
token.tsTokenManager: cache, single-flight refresh, user / SA impersonation / IAP providers
secret-manager.tsREST fetch for projects/.../secrets/...
gcp-env.tsImported first from bin.ts to tame metadata server lookups
testdata/mock-iap-server.tsTests

TokenManager must not mint SA private keys. Concurrent refreshes share a per-(identity, audience, scopes) lock.

adapters/http/ ​

RecipeRuntime: fetch named recipes, JWT/TTL cache, optional loopback expose via proxy. identity.ts maps recipe auth onto TokenManager.

adapters/proxy/ ​

FileRole
proxy.tsHTTP reverse proxy, route match, token inject, CORS preflight, request ring, X-Devctl-Request-ID, optional LLM body-capture tee (via LlmCaptureSink)
grpc-proxy.tsh2c loopback → h2+TLS upstream with the same auth
tracing.tsSpan creation around proxy hops
security.test.tsLoopback and header guarantees

Token endpoint (GET /token) is loopback + internal token (DEVCTL_INTERNAL_TOKEN). Never log Authorization.

adapters/storage/ ​

FileRole
storage.tshomeDir, session dir, lock, socket, rpc-token, MCP token, state.json, bootstrap logs
logs.tsLogManager ring, persist, export, parsers
worker-log-store.tsWorker thread wrapper (log-worker.ts + protocol) so ingest does not block the daemon
spans.tsIn-memory span forest
credentials.tsOS keychain with file fallback 0600

adapters/llm/ ​

LlmCoordinator polls pull sources; litellm.ts / litellm-map.ts map spend logs. The push proxy driver (proxy-driver.ts) is fed out-of-band by proxy-capture.ts (the LlmCaptureSink the HTTP proxy calls) + proxy-capture-map.ts (JSON/SSE bodies → ingest). store.ts is the ring; factory.ts registers drivers including plugins.

adapters/traffic/ ​

TrafficCallRing is the in-memory store (redact at upsert). ProxyTrafficSink implements TrafficCaptureSink for HTTP and gRPC proxies: per-route inspect.enabled, skip recipe expose hops, tee bodies up to max_bytes, never fail the proxied call.

adapters/telemetry/ ​

otlp-http.ts — optional loopback OTLP HTTP receiver feeding LogStore / SpanStore.

adapters/secrets/ ​

Detector — name markers + regexes; extra lists from config. Shared redaction helpers also live in shared/redaction.ts for presentation.

adapters/net/ ​

Port allocation (assignPorts, freePort), MCP default port helper.

adapters/plugins/ ​

registry.ts loads plugins[].path (Bun file plugins). Extension points: health, identity/token, environment sources, log parsers, proxy middleware, LLM sources. PLUGIN_SDK_VERSION. Failures skip that plugin and log; unknown configured types after load are validation errors.

Public import path for plugin authors: app/src/plugin-sdk.ts.

adapters/doctor/ ​

Implements DoctorRunner. Checks: tools, ports, containers, ADC, impersonation, APIs, IAP credentials files (static inspect; live mint is separate). Never auto-enables cloud APIs.

adapters/update/ ​

GitHub releases for devctl update.

adapters/system/ ​

clock.ts, filesystem.ts, host-stats.ts (CPU/mem for the sampler).

Rule of thumb ​

If a file talks to the OS, Google, Docker, or the network, it is an adapter. If it decides whether a transition is legal, it is domain. If it sequences a start wave, it is application.

Released under the MIT License. Use at your own risk.