Sign inSign up

cenk1cenk2/hermes-bridge-linear

By cenk1cenk2

•Updated 7 days ago

Bridges Linear agent session webhooks to Hermes runs.

Image
0

1.5K

cenk1cenk2/hermes-bridge-linear repository overview

⁠hermes-bridge-linear

Bridges Linear agent session webhooks to Hermes runs and posts run progress back as Linear agent activities. Talks directly to a Hermes⁠ API server — any deployment that exposes /v1/runs.

⁠Image

docker run --rm -p 8080:8080 cenk1cenk2/hermes-bridge-linear:latest
TagSource
latestThe latest release.
v<version>The release @kilic.dev/hermes-bridge-linear@<version> created by semantic-release.

⁠Environment

Durations are milliseconds unless noted.

VariableDefaultDescription
PORT8080Port the HTTP server binds to.
AGENT_NAMEHermesName the agent goes by in its activities, e.g. labrat: the acceptance line and the answer to a user who is not allowed.
LOG_LEVELinfoLowest level logged: error, warn, info, debug or verbose.
LOG_FORMATjsonjson for one JSON object per line, text for readable local lines.
REDIS_URLrequiredRedis or Valkey holding every queue and all shared state.
QUEUE_PREFIXlinear-hermes-bridgePrefix of every Redis key and queue.
QUEUE_RETENTION_COMPLETED3600Seconds a completed job is kept.
QUEUE_RETENTION_FAILED86400Seconds a failed job is kept.
QUEUE_TRANSACTION_RETRIES10Attempts of a Redis transaction that keeps conflicting.
LINEAR_CLIENT_IDrequiredClient id of the Linear app, for the client credentials token.
LINEAR_CLIENT_SECRETrequiredClient secret of the Linear app.
LINEAR_WEBHOOK_SECRETrequiredSigning secret of the Linear webhook.
LINEAR_SCOPESread,write,app:assignable,app:mentionableScopes of the minted token; a mint with other scopes revokes every app token.
LINEAR_TOKEN_URLhttps://api.linear.app/oauth/tokenOAuth token endpoint for the mint.
LINEAR_ACTIVITY_RATE_LIMIT_MAX1Activities posted per rate limit window, across replicas.
LINEAR_ACTIVITY_RATE_LIMIT_DURATION1000Length of the rate limit window.
LINEAR_WEBHOOK_TIMEOUT4000Time a webhook may spend queueing its event before it answers 503.
LINEAR_WEBHOOK_INSTRUCTIONSnoneInstructions every Linear input carries.
LINEAR_WEBHOOK_ALLOWED_USERSComma-separated Linear user ids allowed to trigger the agent: the session creator on created, the prompt author on prompted. Anyone else gets one response and no run. Empty allows everyone.
LINEAR_SESSION_TTL86400000Lifetime of seen stops, a session's last stop, tool arguments and plan state.
LINEAR_SESSION_TRUNCATE_PARAMETER200Characters of a tool argument shown in its action.
LINEAR_SESSION_TRUNCATE_RESULT1000Characters of a tool result shown in its action.
LINEAR_RECOVERY_AGE86400000Age of the oldest session the boot sweep resumes or closes.
LINEAR_RECOVERY_GRACE60000Age a session needs before the boot sweep; Linear retries younger events.
LINEAR_RECOVERY_PAGE_SIZE50Sessions fetched per page by the boot sweep.
LINEAR_RECOVERY_PAGES20Pages of sessions the boot sweep reads at most.
HERMES_URLrequiredBase URL of the Hermes API server, e.g. https://hermes.example.com/v1.
HERMES_API_KEYrequiredKey sent to the Hermes API server.
HERMES_INSTRUCTIONSnoneInstructions of a run whose input carries none, that is when LINEAR_WEBHOOK_INSTRUCTIONS is not set.
HERMES_EVENTS_IDLE_TIMEOUT120000Silence on a run event stream before it is dropped and the run is polled.
DRIVER_SEEN_TTL86400000Lifetime of a seen idempotency key.
DRIVER_QUEUE_LOCK_TTL30000Lifetime of a thread lock.
DRIVER_QUEUE_LOCK_RENEW_INTERVAL10000Renewal interval of a held thread lock.
DRIVER_QUEUE_SWEEP_INTERVAL1000Interval of the sweep for threads with due work.
DRIVER_BACKOFF_INITIAL5000First retry delay while a run create gets 429, a 5xx or no connection.
DRIVER_BACKOFF_MAX60000Largest retry delay.
DRIVER_POLICY_BATCHtrueJoin the inputs queued behind a run into one run.
DRIVER_POLICY_STEERtrueSteer a follow-up into the running run instead of queueing it.
DRIVER_POLICY_RESUBMIT_MAX2New runs in the same Hermes session for a run that ends interrupted.
DRIVER_POLICY_BACKOFF_WINDOW600000Time Hermes may stay busy or unavailable before the thread fails.
DRIVER_POLICY_APPROVALdeny-stopdeny-stop stops a run after denying its approval request, deny-continue lets it go on.
DRIVER_FOLLOW_LEASE_TTL30000Lifetime of a run lease; another replica takes the run over once it expires.
DRIVER_FOLLOW_LEASE_RENEW_INTERVAL10000Renewal interval of a held run lease.
DRIVER_FOLLOW_SWEEP_INTERVAL5000Interval of the sweep for runs nobody follows.
DRIVER_FOLLOW_POLL_INTERVAL5000Interval between polls of a run without a stream.
DRIVER_FOLLOW_RETENTION86400000Time a finished run's record is kept.
DRIVER_HEARTBEAT_IDLE1200000Silence in a thread before it reports idle.
DRIVER_HEARTBEAT_SWEEP_INTERVAL60000Interval of the idle sweep.

⁠Routes

MethodPathDescription
GET/healthzLiveness: answers 200 ok.
GET/readyzReadiness: answers 200 ok, and 503 once a shutdown starts draining.
POST/v1/hooks/linearLinear agent session webhooks: 400 on a bad signature, a stale timestamp or a payload that fails the schema, 503 when the event could not be queued, else 200.
anyany otherAnswers 404.

⁠Logs

Every line carries a message that is a complete sentence fixed per event, its source class as context, and its ids, numbers and reasons as fields at the root of the JSON object ({"level":"log","message":"Created a run for the thread.","context":"DriverThreadService","run":"...","thread":"...","replayed":false}); text prints the same fields inline. Durations are durationMs; tokens and bodies are never logged.

  • info: one line per HTTP request (method, path, status, duration, remote address; /healthz and /readyz only at debug), webhook verification or rejection with the Linear-Delivery and Linear-Event headers, each session event, acknowledgement and thread input, run creation, busy backoff, steers, stops, follows and takeovers, finished runs with status and duration, posted activities, token mints, Redis connections, the recovery sweep summary, the drain on shutdown and the runs and threads it hands over.
  • debug: every run stream event, Hermes call (method, path, status, duration), queued and coalesced activity and session update, thread lock and run lease acquire, renew and release, and Redis transaction retry.
  • warn and error: anything retried, dropped or failed, with its error.

⁠Signed fixtures

Run from apps/linear, tests/post-fixture.ts signs a fixture from tests/testdata with the webhook secret for the webhook URL given as its second argument, stamps a fresh webhookTimestamp, a fresh agentActivity.id and a fresh Linear-Delivery header, and POSTs it. It runs on Node 26 as is, since Node strips the types. Name a session Linear already opened to watch its activities land:

LINEAR_WEBHOOK_SECRET=... node tests/post-fixture.ts tests/testdata/created-delegation.json https://bridge.example.com/v1/hooks/linear <agentSessionId>

⁠Development

The application lives in apps/linear of the workspace and runs on the shared core in packages/core; see the repository README.

pnpm install
pnpm lint
pnpm test
pnpm build
pnpm --filter @kilic.dev/hermes-bridge-linear start

Tag summary

Content type

Image

Digest

sha256:e5a4b55cc…

Size

79.9 MB

Last updated

7 days ago

docker pull cenk1cenk2/hermes-bridge-linear