coworkobserve

package
v0.10.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 18, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package coworkobserve adds Claude Cowork observation to the managed-observe daemon, reusing the existing Claude Code pipeline.

Cowork runs the bundled Claude Code CLI inside a per-session VM whose root filesystem is rebuilt on every boot, so hooks cannot be baked into the image. What does survive is the per-session CLAUDE config dir, which Cowork mounts from the host at:

~/Library/Application Support/Claude/local-agent-mode-sessions/<account>/<workspace>/local_<session>/.claude/

This is the guest's $HOME/.claude — the "user" settings tier, which Cowork's CLI loads at startup. Two host-side loops run inside the daemon:

  • injector: writes settings.json with a PreToolUse command hook into each new per-session .claude dir before the in-VM CLI initializes. The hook appends every tool event to a host-mounted spool file in the session dir (no in-VM network needed — the dir is a host mount).
  • collector: tails those spool files and replays each event into the daemon's existing localruntime socket as agent "cowork", reusing the same classify -> store -> managedstream -> ledger path Claude Code uses.

Modes

The posture follows the deployment-level managed.json mode, like every other hook edge. In observe mode the hook is fire-and-forget and nothing blocks. In enforce mode the hook wraps each event in an envelope with a request id, waits up to 10s for the daemon's verdict at kontext-cowork-decisions/<rid>.json, and emits it verbatim — the bundled CLI honors the permissionDecision. No verdict in time means the hook emits deny ("Kontext daemon unavailable"): fail-closed, mirroring the sidecar.

Caveats

Integrity: the spool is written by code running inside the VM, so anything in the VM (including a prompt-injected agent) can append forged events or withhold real ones. Cowork-tagged ledger entries are self-reported telemetry, not attested records. Enforcement gates agent-via-CLI actions only: in-VM code that bypasses the CLI was never reachable by a hook, and a tool call that lands before settings injection runs unguarded (the health heartbeat surfaces such sessions). A hook killed at the CLI's own timeout is treated by Claude Code as allow, so fail-closed is best-effort within the timeout budget.

Delivery: events are replayed at-least-once. A replay that fails after a partial send is retried, so the ledger may very occasionally see a duplicate; it never silently drops a complete spool line.

Coupling: the session-dir layout, the host mount, and the user-tier settings load are undocumented Cowork internals; an update can break observation without an error. The health heartbeat (sessions seen vs hooked vs spooling) exists so that breakage is visible in diagnostics.

Deployment: run the daemon in the session user's context (LaunchAgent, not a root LaunchDaemon) — the injector writes settings.json into the user's ~/Library and root-owned files there may confuse Cowork or the VM mount's UID mapping.

Index

Constants

View Source
const (
	// EnvEnabled enables Cowork observation when set to a truthy value.
	EnvEnabled = "KONTEXT_COWORK_OBSERVE"
	// EnvSessionsRoot overrides the Cowork sessions root for testing.
	EnvSessionsRoot = "KONTEXT_COWORK_SESSIONS_ROOT"
)

Variables

This section is empty.

Functions

func DefaultSessionsRoot

func DefaultSessionsRoot() string

DefaultSessionsRoot returns the standard Cowork sessions root on macOS.

func Enabled

func Enabled() bool

Enabled reports whether Cowork observation is turned on via the environment. Managed installs should prefer the cowork_enabled field in managed.json; the env var remains as a development/debugging override.

func Run

func Run(ctx context.Context, opts Options)

Run starts the injector and collector loops and blocks until ctx is cancelled.

Types

type Options

type Options struct {
	// SocketPath is the daemon's localruntime socket (where events are replayed).
	SocketPath string
	// SessionsRoot is the Cowork sessions root; defaults to the standard path.
	SessionsRoot string
	// StatePath persists collector spool offsets across daemon restarts so a
	// restart does not re-replay already-ingested events as duplicate ledger
	// entries. Empty means offsets are kept in memory only.
	StatePath string
	// Mode selects the injected hook: observe installs the fire-and-forget
	// spool append, enforce installs the decision round-trip that blocks the
	// tool until the daemon's verdict lands. Defaults to observe.
	Mode guardhookruntime.Mode
	// PollInterval controls how often the loops scan; defaults to 250ms.
	PollInterval time.Duration
	Diagnostic   diagnostic.Logger
}

Options configures the Cowork observer loops.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL