Commit Graph
9 Commits
Author SHA1 Message Date
Dotta 9964b034bb feat(runner): add hidden server PRP coordinator (#12176)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The Paperclip Runner needs a narrow server trust boundary before an
adapter can start it.
> - The package has durable runner transport, but the server does not
host or authorize that transport.
> - Native persistence exists, but no writer connects PRP events to
those records.
> - A direct adapter must not enter this path by accident.
> - This pull request adds a hidden, run-bound PRP server coordinator.
> - The benefit is a recoverable server boundary that remains
unavailable to normal execution.

## Linked Issues or Issue Description

Refs #11962

Refs #12129

Refs #12169

**Subsystem affected**

Cross-cutting. The change affects the runner package and server
orchestration.

**Problem or motivation**

The server cannot authenticate runnerd, commit PRP events before ACK,
authorize semantic tools, or enter native finalization from a durable
runner result. The application must have this hidden boundary before a
guarded adapter can use the runner.

**Proposed solution**

Add an authenticated PRP WebSocket authority and register it only for
one exact persisted native Codex run. Bind each connection and event to
the company, issue, agent, run, runner, session, turn, item, and
verified runner identity. Commit each event before its cumulative ACK.
Project only authorized same-task read tools. Rebuild the accepted
result and finalization record from durable result and terminal events.

**Alternatives considered**

The server could expose a broad runner API key or route semantic calls
through existing adapter endpoints. Those options grant too much
authority and weaken replay recovery. The server could also add the
user-facing adapter in this pull request. That option would mix rollout
selection with the transport trust boundary and make legacy
compatibility harder to review.

**Roadmap alignment**

This work supports the shipped enforced-outcomes, governed-tool, and
self-healing-run milestones. It does not add a new roadmap surface.

## What Changed

- Add the durable PRP server authority with one-use bootstrap tickets,
reconnect leases, encrypted frames, bounded state, cumulative ACKs, and
idempotent commands.
- Add `/api/runner/v1/connect/:runId`. Derive its `ws://` or `wss://`
URL from the configured Paperclip API URL.
- Register one authority only after the coordinator verifies the
complete native Codex run binding.
- Commit validated PRP events to `heartbeat_run_events` before ACK.
Reject source gaps and conflicting replays.
- Rebuild accepted results and finalization records from durable result
and terminal events. Enforce finalization owner leases and retry times.
- Project five same-task read operations. Recheck run, agent, task, and
company authority for each call.
- Keep the route hidden. No adapter selects this coordinator, and no
code starts runnerd.
- Vendor the compiled runner TypeScript runtime into the server package
while keeping the workspace package development-only for the server.
- Document the package, database writer, run-log payload, and credential
exclusions.

## Verification

- Run `pnpm --filter @paperclipai/paperclip-runner check:all`. All
TypeScript protocol checks and 69 Vitest tests pass, including
commit-before-ACK crash recovery. All 43 Rust unit tests and 13 Rust
integration tests pass. Conformance and replay parity pass.
- Run the focused server WebSocket, coordinator, package-build, and
startup-wiring suites. All 26 tests pass, including a clean-checkout
reproduction with the runner `dist` directory absent.
- Run `pnpm -r typecheck`.
- Run `pnpm test:run`.
- Run `pnpm build`.
- Confirm that the diff contains 19 files. Confirm that it contains no
workflow or `pnpm-lock.yaml` change.

## Risks

- The server installs the WebSocket route at startup. An unregistered or
malformed run path fails closed and creates no native record.
- Bootstrap tickets are one use. The private state directory uses mode
`0700`, and the state file uses mode `0600`. The file stores derived
authentication verifiers and never stores raw tickets or lease tokens.
- The journal has explicit frame, command, event-window, and file-size
bounds. A bound violation closes the runner connection or rejects the
command.
- A runner event reaches the database before its ACK. A crash between
event commit and ACK causes a byte-equivalent replay, not a second
logical effect.
- The coordinator accepts only an existing queued or running native
Codex row with exact company, task, agent, runner, session, and
completion-contract ownership.
- Existing direct adapters do not call this service. They keep their
current execution, transcript, result, and finalization paths.
- The server has no production dependency on the private runner package.
Its build copies the compiled runtime into `server/dist`; the workspace
link is development-only. This adds no external package and does not
change the lockfile.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex with GPT-5. The exact deployment ID and context-window
size are not exposed. The model used agentic reasoning, repository
tools, code execution, and test execution.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-08-25 14:17:14 -05:00
Devin Foley 2c53437fc9 fix(server): authenticate cloud-proxied browsers on the live-events websocket (#11290)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The UI receives live run/issue events over a websocket at
`/api/companies/:id/events/ws`; the server authorizes upgrades with a
bearer token or a Better Auth session
> - On a cloud-managed deployment, browsers authenticate through trusted
`x-paperclip-cloud-*` headers injected by the managing front door — they
never hold a local Better Auth session, and the Express middleware lane
that understands those headers is not consulted for websocket upgrades
> - Every browser websocket upgrade behind the front door therefore
resolves no identity and is rejected 403: the live-events socket has
never connected on a managed instance, leaving permanent reconnect churn
and console failure noise while the UI silently degrades to polling
> - This pull request adds a cloud-actor lane to the upgrade
authorization, reusing the same trusted-header resolver the HTTP
middleware uses
> - The benefit is working realtime updates on managed instances, an end
to the reconnect churn, and unchanged self-hosted behavior

## Linked Issues or Issue Description

No existing issue. Description follows the bug template:

**What happened?**

On a cloud-managed instance, the browser console shows `WebSocket
connection to 'wss://…/api/companies/<id>/events/ws' failed:` repeating
indefinitely for every company, on a healthy instance. The server
rejects each upgrade with 403 because `authorizeUpgrade` in
`server/src/realtime/live-events-ws.ts` only knows bearer tokens and
Better Auth sessions, while cloud-proxied browsers authenticate via
`x-paperclip-cloud-*` trusted headers (handled only by the Express
`actorMiddleware` lane in `server/src/middleware/auth.ts`).

**Expected behavior**

A browser that authenticates through the trusted cloud headers can open
the live-events websocket for any company in its membership scope,
exactly as it can call the HTTP API for those companies.

**Steps to reproduce**

1. Run Paperclip in `authenticated` mode behind a proxy that injects the
`x-paperclip-cloud-*` headers with a valid
`PAPERCLIP_CLOUD_TENANT_SERVER_TOKEN`.
2. Load any company page in a browser (no local Better Auth session).
3. HTTP API calls succeed; every `/events/ws` upgrade is rejected 403
and the UI retries forever.

## What Changed

- `server/src/middleware/auth.ts`: `resolveCloudTenantActor` now accepts
a minimal `CloudActorHeaderSource` (`header(name)`) instead of an
Express `Request` — `Request` satisfies it unchanged — plus
`cloudActorHeaderSourceFromHeaders` to adapt raw
`IncomingMessage.headers`.
- `server/src/realtime/live-events-ws.ts`: `authorizeUpgrade` gains an
injected `resolveCloudActor` lane, tried before the Better Auth session
fallback in `authenticated` mode. A resolved cloud actor is
authoritative: the upgrade is authorized only for a company in the
actor's membership scope (`companyIds`, the same scope the HTTP lane
grants). Absent/unresolvable cloud headers fall through to the session
path.
- `server/src/index.ts`: wires `resolveCloudActor` through
`resolveCloudTenantActor` + the header shim. The resolver self-gates:
without `PAPERCLIP_CLOUD_TENANT_SERVER_TOKEN` and a matching trust token
it returns null, so self-hosted deployments never take this path.
- Tests: upgrade authorized for an in-scope company (session resolver
not consulted), rejected for an out-of-scope company, fall-through to
session auth when no cloud actor resolves; header-shim resolution from a
raw lowercased header map including `string[]` values.

## Verification

- `pnpm vitest run server/src/__tests__/live-events-ws.test.ts
server/src/middleware/cloud-tenant-actor.test.ts` — 25 tests pass.
- `pnpm typecheck` in `server/` — clean.
- Not verified live end-to-end: that requires a managed instance running
this build; the direct probe evidence (HTTP authenticated fine, every WS
upgrade 403) matches the code path exactly.

## Risks

Low risk. The new lane only activates when the deployment configures the
cloud trust token and the request presents it; both checks already
protect the HTTP lane. Authorization scope is the same `companyIds` set
the HTTP middleware computes (primary stack company plus the user's real
membership rows). The cloud resolver's user/company materialization
writes are debounced (existing behavior shared with the HTTP lane), so
websocket reconnect storms do not amplify database writes. Self-hosted
instances see no behavioral change, covered by the fall-through test.

## Model Used

- Claude (Anthropic), Claude Fable 5 (`claude-fable-5`), via Claude Code
CLI with extended thinking and tool use (code search, edit, test
execution; diagnosis included live websocket handshake probes against a
managed instance).

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-08-12 11:22:50 -07:00
Devin FoleyandPaperclip bcac517f3b Add browser SSH terminal for custom image setup (#8911)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Environment sandboxes already support custom image creation and
refresh through a temporary SSH setup session.
> - The existing workflow makes operators copy an SSH command into an
external terminal before they can install packages or make image
changes.
> - That extra context switch is slower, easier to get wrong, and less
integrated with the setup session Paperclip already tracks.
> - This pull request adds an embedded browser SSH terminal for custom
image setup, so operators can start working in the target sandbox
directly from the environment configuration flow.
> - The implementation uses short-lived websocket attachment tokens,
session-lifetime SSH host-key pinning, and server-managed terminal
cleanup so the feature fits the existing setup-session boundary.
> - The benefit is a smoother custom image creation and refresh
experience without asking users to leave Paperclip for routine sandbox
setup work.

## Linked Issues or Issue Description

No public GitHub issue exists.

### Subsystem affected

Cross-cutting: `server/` custom image setup APIs and websocket handling,
`ui/` environment configuration UI, and shared custom image contracts.

### Problem or motivation

Custom image creation and refresh require an operator to open a separate
SSH client, paste the command shown by Paperclip, perform setup work,
then return to the browser to finish the image flow. This is functional
but awkward for a setup process that already starts and tracks a
temporary sandbox session.

### Proposed solution

Embed an SSH terminal in the custom image setup UI. When a setup session
exposes an SSH payload, Paperclip should open a browser terminal backed
by a server-side websocket session, let the operator run setup commands
in-place, and then close the terminal when setup is finished, cancelled,
expired, or disconnected.

### Alternatives considered

- Keep the existing copy/paste SSH command workflow. This remains a
fallback, but it does not streamline the common path.
- Put SSH credentials directly into websocket URLs. This was avoided so
terminal authentication can happen in an explicit first websocket auth
frame rather than in logged URLs.
- Trust the SSH host blindly for every reconnect. This PR instead pins
the observed host-key fingerprint for the setup-session lifetime.

### Roadmap alignment

This fits the roadmap theme of making agent workspaces usable in more
remote and sandboxed environments while preserving Paperclip's
control-plane model.

### Additional context

Public GitHub search did not find a duplicate issue or PR for `custom
image terminal ssh` in `paperclipai/paperclip`.

## What Changed

- Added server-side terminal session tracking for custom image setup
sessions, including connect-token issuance, websocket attachment,
expiry, resize, input, and shutdown handling.
- Added an embedded browser terminal to the custom image creation and
refresh flow when a setup session provides SSH connection details.
- Moved terminal token authentication out of the websocket URL and into
the first websocket JSON auth frame.
- Added SSH host-key SHA-256 pinning for each terminal session and
documented the provider convention for username-embedded SSH
credentials.
- Updated the custom image environment API and UI so the setup terminal
can open, reconnect, show status, authenticate, resize, and remain
active for the setup-session lifetime once attached.
- Kept custom image setup routes company-scoped and closed active
terminal sessions on setup finish/cancel.
- Added focused unit/integration/UI coverage for token expiry,
setup-session expiry, websocket close paths, host-key pinning, and
terminal session lifecycle behavior.
- Removed the generated lockfile delta from the PR; CI owns temporary
lockfile regeneration for manifest-changing PRs.

## Verification

- `pnpm exec vitest run
server/src/__tests__/server-startup-feedback-export.test.ts
server/src/__tests__/environment-custom-image-terminal-ws.test.ts
server/src/services/environment-custom-image-terminal-sessions.test.ts
server/src/__tests__/environment-custom-image-routes.test.ts
packages/shared/src/environment-custom-images.test.ts
ui/src/pages/CompanyEnvironments.test.tsx`
  - 6 test files passed
  - 58 tests passed
- `pnpm --filter @paperclipai/server typecheck`
- `pnpm --filter @paperclipai/ui typecheck`
- `pnpm --filter @paperclipai/server build`
- `pnpm --filter @paperclipai/ui build`
- `pnpm run typecheck:build-gaps`
- `git diff --check`
- Local sensitive-content scan over the PR diff using patterns for API
keys, private keys, private hostnames, local paths, token fields, and
credential-like strings.
- Findings were limited to removed URL-token code and synthetic test
placeholders such as `ssh-token-secret` and
`terminal-token-terminal-token-123456`.
- No real credentials, private hostnames, local filesystem paths, or
instance-local links were found.
- Remote PR checks were green after the implementation commit, including
Build, Typecheck + Release Registry, General tests, serialized server
suites, e2e, verify, Socket, Snyk, Superagent, and Greptile 5/5.
- Post-merge PR hardening on July 3, 2026: merged `origin/master` at
`47448721e` into the branch, resolved the `CompanyEnvironments.tsx`
import conflict, reran focused tests, server/UI typechecks, server/UI
builds, `pnpm run typecheck:build-gaps`, and `git diff --check`, scanned
the final diff for sensitive content, pushed `4b43558cc`, and confirmed
all remote checks plus Greptile 5/5 were green.
- PR metadata correction on July 3, 2026: changed the title/body framing
from bug-fix language to feature-request language. No source files
changed for this metadata-only update.

## Risks

- Moderate surface area because this adds websocket routing,
setup-session runtime state, package dependencies, and a new custom
image UI path.
- New websocket attachments still require valid short-lived tokens;
established terminal sessions remain bounded by setup-session expiry,
explicit finish/cancel, client close, or server shutdown.
- The terminal-session store is in-memory, so active terminal websocket
tokens and host-key pins do not survive server restarts.
- SSH host-key verification uses session-lifetime TOFU pinning because
the current provider payload does not expose a trusted host-key
fingerprint.
- The external SSH command remains important as a fallback if a browser,
proxy, or network environment cannot sustain the websocket terminal.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI Codex, GPT-5 coding agent with shell/tool execution. Context
window size was not exposed in this runtime.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-03 16:44:21 -07:00
Aron PrinsandPaperclip e93d78b46c fix(server): harden live events upgrade sockets (#8383)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The server exposes live event updates to board and agent clients
over WebSocket upgrade requests
> - WebSocket upgrade authorization can be asynchronous, leaving the raw
HTTP upgrade socket in server-owned code before `ws` takes over
> - If the client disconnects during that authorization window, the
server can still try to reject or upgrade a closed socket
> - A raw socket write after peer disconnect can emit `EPIPE` /
`ECONNRESET`, and without a listener that can become process-fatal
> - This pull request hardens the pre-`ws` upgrade socket path and adds
regression coverage for disconnect/error races
> - The benefit is that live event reconnect churn degrades gracefully
instead of risking a server crash

## Linked Issues or Issue Description

External public context: Refs
https://github.com/aronprins/paperclip-desktop/issues/14

No matching open upstream issue or PR was found when searching
`paperclipai/paperclip` for `EPIPE`, `rejectUpgrade`, `live-events-ws`,
`websocket upgrade`, and related socket-write terms.

### Bug report

**What happened?**

The live events WebSocket upgrade handler could write a rejection
response to the raw upgrade socket after the peer had already
disconnected during async authorization. A transport-level `EPIPE` or
similar socket error on that raw socket can terminate the server process
if it is emitted without an error listener.

**Expected behavior**

The server should not write to destroyed/non-writable upgrade sockets,
should tolerate raw socket errors while authorization is pending, and
should not call `handleUpgrade()` after the socket is no longer
writable.

**Steps to reproduce**

1. Start a Paperclip server with live events enabled.
2. Open a raw WebSocket upgrade request to
`/api/companies/:companyId/events/ws`.
3. Disconnect the client before async authorization resolves.
4. Let the server take the reject or upgrade path.
5. Observe that the pre-fix path can still write to or upgrade a closed
socket.

**Paperclip version or commit**

Reproduced by static inspection on `master` before this PR at
`950484d20`.

**Deployment mode**

Any mode using live event WebSocket upgrades. The report was originally
observed from local Desktop embedding, but the vulnerable code is in the
server package.

## What Changed

- Added a writable-state guard for raw upgrade sockets before rejecting
or completing an upgrade.
- Changed rejection responses from raw `write()` + `destroy()` to
guarded `end()` with warning logging if rejection fails synchronously.
- Attached a temporary raw socket error listener during the async
upgrade authorization window and cleaned it up on socket close or
successful `ws.handleUpgrade()`.
- Added regression tests for rejecting after an early socket close and
for handling raw socket `error` events while authorization is pending.

## Verification

- `pnpm exec vitest run server/src/__tests__/live-events-ws.test.ts`
- `pnpm --filter @paperclipai/server typecheck`
- `git diff --check`

## Risks

- Low risk: the change is scoped to the live-events WebSocket upgrade
path before `ws` takes ownership of the socket.
- Rejected upgrade responses now use graceful `socket.end(...)`; clients
should still receive the same HTTP status text when the socket is
writable.
- The temporary error listener is removed before successful
`handleUpgrade()` so normal WebSocket client error handling remains
owned by the existing `connection` path.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI Codex, GPT-5 coding agent with repository-aware tool use, shell
command execution, GitHub connector access, and local code editing.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-06-20 11:32:49 -07:00
zvictor e5049a448e update typing to node v24 from v20 2026-03-05 14:36:00 -03:00
DottaandClaude Opus 4.6 f60c1001ec refactor: rename packages to @paperclipai and CLI binary to paperclipai
Rename all workspace packages from @paperclip/* to @paperclipai/* and
the CLI binary from `paperclip` to `paperclipai` in preparation for
npm publishing. Bump CLI version to 0.1.0 and add package metadata
(description, keywords, license, repository, files). Update all
imports, documentation, user-facing messages, and tests accordingly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 08:45:26 -06:00
ForgottenandClaude Opus 4.6 32cbdbc0b9 feat: authenticate WebSocket upgrades in authenticated mode
Resolve Better Auth sessions from raw headers for WS upgrade
requests. Verify instance admin or company membership before
allowing live-events connections in authenticated mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 08:39:20 -06:00
ForgottenandClaude Opus 4.6 e1f2be7ecf feat(server): integrate Better Auth, access control, and deployment mode startup
Wire up Better Auth for session-based authentication. Add actor middleware
that resolves local_trusted mode to an implicit board actor and authenticated
mode to Better Auth sessions. Add access service with membership, permission,
invite, and join-request management. Register access routes for member/invite/
join-request CRUD. Update health endpoint to report deployment mode and
bootstrap status. Enforce tasks:assign and agents:create permissions in issue
and agent routes. Add deployment mode validation at startup with guardrails
(loopback-only for local_trusted, auth config required for authenticated).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 14:40:32 -06:00
ForgottenandClaude Opus 4.6 c9c75bbc0a Implement agent runtime services and WebSocket realtime
Expand heartbeat service with full run executor, wakeup coordinator,
and adapter lifecycle. Add run-log-store for pluggable log persistence.
Add live-events service and WebSocket handler for realtime updates.
Expand agent and issue routes with runtime operations. Add ws dependency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 12:24:43 -06:00