Tags give the ability to mark specific points in history as being important
-
v0.13.0
008b397e · ·v0.13.0 Peen now has a complete workspace-first controller flow. The bundled browser client opens or resumes a workspace session, shows live work as it happens, and gives clear feedback when a workspace or harness definition needs repair. - Breaking: `message.send.data.workdir` is no longer accepted. Open or resume the workspace first with `POST /v1/sessions/open`, then send the returned session ID in WebSocket event metadata. This prevents individual messages from changing the directory a durable session owns. - Adds workspace-root discovery and a typed workspace-opening API. The controller rejects missing, non-directory, or out-of-root paths with a specific client-safe error instead of a generic server failure. - Reworks the bundled control surface into a full-height coding chat. It can open an existing child workspace, switch sessions, show thinking, tool calls, output, failures, profiles, and the complete durable session record. - Invalid optional `AGENTS.md`, rules, skills, named agents, event handlers, and hooks no longer prevent a usable workspace from running. Peen logs and stores a durable `harness.warning` event with the skipped source and repair reason, while valid sibling configuration still loads. Unreadable workspaces and resource limits remain hard failures. - Adds `make run-dev` for a local controller using the current host UID and GID. It uses the invoking checkout as its workspace and does not grant Docker socket access unless explicitly requested. - Removes the unused hello-world example service and keeps coverage output scoped to Peen's actual packages.
-
v0.12.0
1d7b576a · ·v0.12.0 Peen now includes a browser control surface at the controller root URL. It connects to the same global WebSocket feed as every other client, and it reads durable state through the public API. No database, configuration, or API migration is needed. - Embeds a static Svelte control surface in the Peen binary and production image. It opens or resumes workspace sessions, shows their durable records, sends WebSocket turns, cancels running work, selects profiles, and keeps the active session view in step with global live events. - Adds `GET /v1/models`, which lists the non-secret models confirmed when the controller started. Each result includes the exact `connection/model` name a client may send as a one-turn model override, its connection, raw model ID, and enforced context window. - Adds the frontend build, typecheck, lint, unit-test, and real-browser checks to the project tooling and CI. Browser diagnostics log only a closed set of safe metadata and never API tokens, message text, or event payloads. - Normalizes generated control-surface text assets before they enter the embedded asset tree, so the release whitespace check accepts every fresh frontend build.
-
v0.11.0
d8a720d0 · ·Child agents now keep their own durable conversations and compaction lineages. Existing databases migrate automatically. No API migration is needed. Hook commands must use the `stateDirectory` in their invocation instead of assuming that hook state lives below `PEEN_CONFIG_DIR`. - Stores each child task, assistant message, tool result, and hook injection in SQLite before the child continues. A child summary stays separate from the parent session, retains immutable direct message membership, and links to the summary it supersedes. - Adds `GET /v1/session/agents/{agentRunId}/messages`, `GET /v1/session/agents/{agentRunId}/compactions`, and `GET /v1/session/agents/{agentRunId}/compactions/{compactionId}`. They expose a child transcript and compaction lineage only to its owning session. - Adds `.claude/rules/*.md`, `.agents/rules/*.md`, and compatible `.claude/skills/` discovery. A standalone `:skill-name` in a user message activates that resolved skill before the first provider request, including for child agents. - Raises the default child-agent depth to five. The child at the limit cannot launch another child. Child prompts now include Peen's base instructions, and child hook command input includes `agentRunId`. - Keeps writable hook state below `PEEN_STATE_DIR` for native workers and in a Docker worker's session-private writable mount. The configuration directory stays read-only for every Docker worker. - Requires session-notice and hook-emitted `data` to be a JSON object before a durable write. Peen renders delivered notices as quoted JSON data, so event text cannot alter the prompt boundary. - Lets an operator select any Docker image reference the daemon can resolve, including a local development image. Worker records keep a repository digest when the daemon supplies one. -
v0.10.1
bbb9285f · ·Maintenance release. No configuration, API, or workspace migration is needed. - Updates the Servicepack baseline to v1.9.3, including its current security maintenance. - Keeps Peen's dependency policy and byte-exact test fixtures project-owned, so future framework updates do not replace them. - Makes the command process-group test wait for the forked process PID to be written before stopping it. This removes a timing-dependent CI failure.
-
v0.10.0
0a155885 · ·An upstream now declares the wire protocol it speaks in `type`. The field was called `provider`, which read as the vendor when the vendor is already the upstream's `name`. A controller that cannot use its Docker socket also stays up instead of refusing to start. - Breaking: every `PEEN_UPSTREAMS` entry renames `provider` to `type`. `{"name":"aigate","provider":"openai",...}` becomes `{"name":"aigate","type":"openai",...}`. The accepted values do not change: `openai`, `anthropic`, and `zai-coding`. An entry left spelling it `provider` is refused at startup, because the unknown key is dropped and the missing type fails validation as `unsupported type ""`. Qualified model references such as `aigate/your-model-id` name the upstream and are unaffected. - A controller that reaches a Docker socket but cannot build a launcher over it now refuses Docker profiles and keeps running, instead of failing to start. A controller run with numeric `--user uid:gid` against an image holding no account for that UID hit this, which stopped deployments whose sessions may never have named a Docker profile. Native profiles were unaffected then and still are. The controller logs the refusal once with `reason=docker_launcher_unavailable` and the socket path. - The host identity failure names `PEEN_HOST_USERNAME` and `PEEN_HOST_HOME`, the two variables that resolve it. It previously reported only the numeric UID it could not look up, which said nothing about the fix. - The production image installs its entrypoint without `COPY --chmod`, so it builds under the classic Docker builder as well as BuildKit. The installed mode and ownership are unchanged. - A worker call whose answer fails to decode returns the zero value alongside its error rather than whatever the failed decode left behind. - The API integration harness sets `PEEN_STATE_DIR`, which the control plane has required since v0.8.0. Without it the harness could not start its container, so that suite had been unable to run. - The execution-form suite bounds one complete turn separately from startup. Sharing the startup budget made the suite fail whenever a turn outran the thirty-second read deadline, which reported a client timeout as a worker failure. -
v0.9.0
3aac6de7 · ·Peen now installs in one command. Both routes build in a pinned Go image, so neither needs a local Go toolchain. - Adds `make install`, which places the built binary at `PREFIX`, defaulting to `~/bin`. It builds first, so it needs Docker and no local Go toolchain, and it warns when `PREFIX` is not on `PATH`. Pass `PREFIX` with `sudo` for a system-wide destination. - Adds `install.sh` at the repository root for a one-shot install: `curl -fsSL https://raw.githubusercontent.com/psyb0t/peen/main/install.sh | bash`. It clones into a temporary directory, builds, installs, and removes the clone on the way out whether or not the build succeeded. `PREFIX` selects the destination and `REF` selects a tag or branch. It requires `git` and `docker` and stops when either is missing. Cloning and running `make install` by hand does the same thing. - The README gains an Install section covering both routes, and docs/deployment.md documents them alongside the existing source, `go install`, and Docker routes. - The README contents list now includes the Docker deployment section the page already carried. - Editorial pass over project comments and documentation prose. No behavior change.
-
v0.8.0
43a977cd · ·Peen is now a control service that starts with no sessions. A client names the workspace it wants, and the returned session ID routes every turn. - `peen run` now starts `control-core` and `control-api` instead of the single `http-server` service. `control-core` opens configuration, SQLite, the provider registry, the workspace policy, and the agent runtime, and reports ready only after those exist. `control-api` depends on it, serves REST, the global WebSocket feed, and metrics, and reports ready only once its endpoint answers a connection. Servicepack stops them in reverse order, so the API stops accepting work before SQLite closes. - Adds local control-client commands: `peen control status`, `peen session open <workspace>`, and `peen session list`. They call the control API over the configured endpoint. A command that finds no controller takes a start lock under `PEEN_CONFIG_DIR`, re-checks while holding it, and starts `peen run` only if one is still absent, so two racing commands produce one controller. No command opens SQLite or starts a second supervisor. `peen control status` never starts a controller, so it can report that none is running. - Adds `peen session attach <session-id>`, which streams one session's live events over the server-side session filter, and `peen session stop <session-id>`, which cancels the session's active turn and reports whether one was running. - Splits the model loop out of the control plane. A session's turns now run in a worker process the controller starts on demand, and the controller keeps SQLite, REST, the WebSocket hub, routing, and worker lifecycle. A worker never opens the control database. It reaches durable state over a private per-session Unix socket carrying `run_turn`, `cancel`, and `shutdown`, and authenticates with a credential minted per worker generation. Only the credential's SHA-256 hash is stored. The raw value goes to the worker on stdin and never reaches a command line, an environment variable, a container label, or a log. - Adds the internal `peen worker` command, which reads one launch document from stdin, connects back to the controller, and serves that session's turns. It is hidden from `--help` because the controller is its only caller. - Every turn, post-start protocol event, job, and child-agent run records the worker generation that produced it in SQLite. The tool surface is the same `tools` package in every environment, so read-before-write hashes, no-replace creation, cancellation, and job signals are unchanged. - Public WebSocket `message.send` now resolves the session's operator-selected profile, ensures that session's worker, and dispatches the turn to it. Global event fan-out happens only after the durable write, so a client never sees an event that a reconnect and replay would not produce. - Adds operator-defined execution profiles through `PEEN_EXECUTION_PROFILES` and `PEEN_DEFAULT_EXECUTION_PROFILE`, with `native`, `docker.sandbox`, and `docker.host-like` as the documented names. A client names a profile and never sends an image, mount, network setting, or capability. An undefined name returns 403 and creates no session. - Adds the native worker launcher, which starts the same installed Peen binary under its `worker` command, and the Docker worker launcher, which creates `peen-worker-<session-uuid>` from the configured image. A worker container carries exactly two labels, `peen.managed=true` and `peen.session=<session-uuid>`, is mounted at literal host paths with the configuration read-only, runs as the controller's host UID, GID, and username, and is refused if that identity is root or incomplete. The supervisor stops or removes a stored container ID only while both labels still match. Unit tests drive a fake Docker client; no live daemon coverage runs. - Adds working `allowPrivilegeEscalation`. A Docker profile with it gives the worker account passwordless sudo inside its own container: the controller starts that container as root, and the image entrypoint creates the account for the controller's host UID, GID, and username, writes `/etc/sudoers.d/peen-worker` for that account alone, and drops to it with `setpriv` before the agent starts. The agent runs as the host user under every profile. Any other profile starts as that identity directly, never touches sudoers, and runs no root process. The image installs sudo and ships no sudoers rule, so sudo authorizes nobody until a profile asks. A `native` profile that sets the flag is refused at startup, because there is no entrypoint there to grant it. - Docker authority is now a startup decision. The controller resolves its socket from `PEEN_DOCKER_SOCKET`, then a `unix://` `DOCKER_HOST`, then `/var/run/docker.sock`, and registers a Docker launcher only when one is reachable. Without it a session on a Docker profile is refused outright. Peen never falls back to a native worker, which would run tools on the host after the operator asked for a container. - Adds `PEEN_WORKER_SOCKET_DIR`, `PEEN_DOCKER_SOCKET`, and `PEEN_WORKER_IMAGE`. - Breaking: adds a required `PEEN_STATE_DIR`, and `PEEN_CONFIG_DIR` no longer holds durable state. `PEEN_CONFIG_DIR` is the global configuration and harness layer, and it is the one directory a Docker worker receives, read-only. `PEEN_STATE_DIR` holds SQLite, the audit logs, and the worker socket root, and no worker receives it. Peen refuses to start when the two are the same path or one sits inside the other. Before this, the configuration mount carried `peen.db` and the audit logs into every Docker worker, so one session could read every other session's transcript. `PEEN_WORKER_SOCKET_DIR` and `PEEN_LOG_DIRECTORY` now default under `PEEN_STATE_DIR`. Move an existing deployment's `peen.db` and `logs` into the new state directory and point both variables at their new homes. The check resolves both paths through their symlinks before comparing, so a state directory that is a link into the configuration directory is refused too, and a path that cannot be resolved refuses startup rather than falling back to the literal string. - A worker now receives only its own session's socket directory, `<root>/<session-uuid>/worker.sock`, instead of the shared socket root. The root lists every live session's socket, so mounting it showed one worker where every other session's controller surface lived. - The worker generation now records the repository digest the daemon reports for the image, so naming a tag still leaves a durable record of the bytes that ran. It previously stored the local image ID from a container inspect and called that a digest, which no registry can resolve. An image the daemon holds no repository digest for, such as one built locally and never pushed, records no digest rather than failing the launch. - Adds the opt-in `make test-docker-worker` target, the image-entrypoint contract test. It creates one test-owned container from a named image inside a disposable root under the repository's gitignored `.testing/` directory, builds the request through the production launch builder, then replaces the worker command with a fixed probe that records what the dropped process can see. It asserts the effective UID, GID, and username, that `sudo -n true` fails, that no Docker socket is present, that the network is unreachable, that the configuration mount is readable while a file planted under the state directory is not, that another session's socket is invisible while this session's own directory is not, and that a file the probe writes carries host ownership. Teardown inspects the exact recorded container ID and acts only while the ownership labels still match. It runs no agent, no model, and no controller database, and it is not part of `make test`. - Adds `GET /v1/execution-profiles`, reporting each profile with `hostRootEquivalent` and a `capabilityWarning`, and `GET /v1/session/workers`, reporting one session's durable worker generations. - A Docker worker now runs the image published alongside the controller running it. Peen takes `PEEN_WORKER_IMAGE` if it is set, then the profile's own `image`, then `psyb0t/peen` tagged with the controller's own build version, so a release runs the worker built beside it without anyone editing configuration. A build with no release tag reports `dev` and names an image no registry holds; set `PEEN_WORKER_IMAGE` to run a Docker worker from a local build. A Docker profile no longer has to carry an `image` of its own. - Removes the worker image rules. A reference previously had to be exactly `psyb0t/peen@sha256:<digest>`: no tag, no other repository. No release could satisfy that for itself, because the digest does not exist until the push that creates it finishes, so every deployment had to read one off the registry by hand afterwards. It also blocked a locally built image, a mirror, and a fork, while stopping nothing: anyone who can set `PEEN_WORKER_IMAGE` already holds the controller's Docker socket and can run any container without asking Peen. Any reference the daemon can resolve is now accepted. A worker container still starts as root so the Peen entrypoint can drop it to the host account, so an image without that entrypoint fails when the worker runs. - The Docker worker launcher now pulls an image the daemon does not already hold. The Engine API's container create does not pull, unlike the docker CLI, which pulls on a 404 and retries, so a worker could not start on a host that had never seen the image. - Fixes `POST /v1/session/jobs/{jobId}/signal`, which recorded every signal as unaccepted while the command kept running. A job's process group is a child of the session's worker, and the endpoint read the controller's own job registry, which is empty after the worker split. The signal now travels to the worker over a new `signal_job` command, and the worker's own signal path both reaches the process group and records the durable request. A session with no live worker still records the request against the durable row and reports that nothing was signalled. - Fixes `POST /v1/session/cancel`, which answered `cancelRequested` and then let the turn run to completion. The endpoint reached the controller's own store, which records the request and fires the cancellation registered in this process. After the worker split the turn's cancellation is registered in the worker, so the controller held nothing to fire and the model loop never stopped. The endpoint now also routes to the session's worker, which is where `peen session stop` ends up too. `control.TurnRouter.CancelSessionTurn` already did the routing and had no callers. - Worker log records now reach the controller's sinks. A worker runs the model loop in its own process, so its records for hook actions, skill activation, child-agent lifecycle, and tool outcomes were written there and never passed through the controller's logging stack. The daily audit file kept controller records only, against the trail `docs/configuration.md` describes. A native worker's output is read from a pipe instead of inherited file descriptors, a Docker worker's is followed from the container, and both are re-emitted at the worker's own level with its session and generation attached. A worker still receives neither the audit directory nor the state directory. - Fixes `GET /v1/session/context-snapshots/{contextHash}`, which returned 500 for every snapshot Peen has written since the endpoint shipped in v0.4.0. The turn writer stores the harness manifest as the JSON array it is, one entry per contributing layer, while the read path decoded it into an object and the schema declared one. The write path only checks `json.Valid`, which an array satisfies, so snapshots stored cleanly and every read failed. `manifest` is now an array of `ContextManifestEntry` carrying `kind`, `name`, `source`, `priority`, and `hash`. This changes a response type inside `/v1` rather than opening a new major, because no client can depend on a shape the endpoint never returned, and because it makes the snapshots already stored in an existing database readable. - `make test-real` now checks what a live turn writes to SQLite. The lifecycle test opens a session, routes the turn through the session metadata, and then reads back one native worker generation in `ready` with no container or image digest, one completed turn, a durable event stream whose sequence never repeats or skips and whose events name only known turns and that one generation, and completed model runs whose per-round provider calls carry real token counts. The wake turn must reuse the same generation. - Adds a live one-session, many-clients and queueing test. Two WebSocket clients attach to one session, and the client that sent nothing still receives the other's live events and its completion, each frame naming the session. A message sent while that turn is running is answered with `queued`, joins the running turn's transcript, and leaves the session with one turn instead of two. - Adds a live cancellation test, which stops a turn already several tool rounds into a real model loop, then checks the WebSocket failure code and that the turn is recorded as cancelled rather than failed. - The real suite renews its WebSocket read deadline per frame instead of spanning the whole turn. A long turn that keeps emitting events no longer fails at a fixed wall-clock limit, and a silent one still does. - Shutdown now stops every session worker after supervised jobs and before SQLite closes, and records each stop, so no worker outlives the process with a durable row still claiming it is ready. - Adds `POST /v1/session/reconfigure`, which moves an idle session to another operator-defined profile. It takes a profile name and a reason and nothing else, refuses an undefined profile with 403, refuses a session with a turn in flight with 409, and stops the session's worker so the next turn starts a new generation under the new profile. Every change is stored in `session_profile_decisions` and readable through `GET /v1/session/profile-decisions`. - The `psyb0t/peen` image now defaults to `run`, so `docker run psyb0t/peen` starts a control plane. The same image is the worker image: the controller creates a container from it with the `worker` command. - Breaking: starting Peen no longer opens a session. Open one with `POST /v1/sessions/open`, which resolves a workspace path to its durable session and creates that session the first time the directory is opened. Opening the same directory again, by any of its names, resumes it. - Breaking: WebSocket `message.send` now takes the session in the event's `sessionId` metadata, replacing the rule that refused a client-selected session. Naming a session routes the message, it does not authorize it: Peen loads the session before starting a turn, so an unknown ID writes no turn record. A deployment with no session and no named session refuses the message. - Adds `GET /v1/sessions`, which lists durable sessions and takes no session header because it is how a client discovers them. - Adds `PEEN_WORKSPACE_ROOTS`, a JSON array of absolute paths a client may open as a workspace. An unset value allows only the process working directory. A path outside every root returns `403 WORKSPACE_NOT_ALLOWED` and creates no session. Peen resolves a requested path through its symlinks before the root check, so an alias of an allowed directory opens the same session and a symlink escaping a root is refused. - Breaking: `pkg/peen` no longer names a session anywhere in its contract. `MessageResult.SessionID`, `ListMessagesRequest.SessionID`, and `SessionDetails.ID` are gone, `Session(ctx, id)` becomes `Details(ctx)`, and `Cancel(ctx, id)` becomes `Cancel(ctx)`. A direct runtime is one workspace and owns its durable session privately. Session IDs exist so a controller can route between workspaces, which is not a problem an embedding caller has. - The binary now calls itself `peen` in its own `--help` and in the `binary` field of every log line, whatever built it. It previously reported the framework's name unless the build passed `-ldflags -X main.appName=peen`, so `go install` and a plain `go build` produced a binary that introduced itself as Servicepack. -
v0.7.0
c4d8fb3f · ·v0.7.0 Peen now binds each running process to one durable session for its startup workspace. Restarting with the same SQLite state and working directory resumes that session. - Breaking: `PEEN_WORKING_DIR` is removed. Start Peen from the workspace you want it to operate in. Docker runs must use `--workdir /workspace` with the project mounted there. - Breaking: WebSocket `message.send` frames no longer accept a client-selected session or workspace. The server reports its startup session ID in event metadata. Use it with the REST read and control endpoints. - Sessions now record their canonical workspace path. The REST session payload includes that path so clients can identify the workspace that owns a trace.
-
v0.6.0
2f824a52 · ·v0.6.0 Peen now ships a dedicated agent package for configuring and operating Peen. - Replaces the inherited Servicepack agent metadata with the `peen` skill for Claude, Codex, and OpenClaw. The skill covers provider configuration, Docker deployment, WebSocket turns, durable session control, and workspace harness layers. - Adds marketplace installation guidance to the README. The central marketplace entry follows this release. - Includes the embedded base `AGENTS.md` in clean checkouts. Lint now rejects a Go embedded asset that Git ignores, preventing a local build from masking a CI compile failure.
-
v0.5.1
6e7b0d4b · ·v0.5.1 Fixes the release checks after v0.5.0. - Execution-form tests now put the session ID in `message.send` metadata, matching the global WebSocket contract. - Peen's test targets and scripts allow thirty minutes per Go test package. Production-image setup can use twenty-five minutes for a cold CI build. - Docker build contexts exclude local plan and coverage directories.
-
v0.5.0
0cfe3836 · ·v0.5.0 WebSocket delivery is now global by default. A client can build and switch conversation tabs from live event metadata while one connection remains open. - Breaking: connect to `GET /v1/ws` and put the client-generated canonical session UUID in `metadata.sessionId` on every `message.send`. The old `?sessionId=` parameter no longer selects the session for a message. It is now an optional outbound filter for one connection. - Global sockets receive accepted events for every session. Clients that want only one conversation may use the optional `?sessionId=` filter or filter events locally by `metadata.sessionId`. - Fixes durable sequence allocation after database error mapping, so a session's first notice, job-output line, and child-agent event persist and replay correctly. - Updates the README and guides with the complete WebSocket frame, global-feed model, durable model-call records, and known-session REST reads.
-
v0.4.1
51a2895f · ·v0.4.1 Fixes the release pipeline, which failed before any job ran. The pipeline now starts, so a tag push builds and publishes the Docker image, creates the GitHub release, and publishes the skill to ClawHub. - Grants the `publish-to-clawhub` job `contents: read`. Under the top-level `permissions: {}`, that job inherited no permissions, so the ClawHub reusable workflow could not be granted the `contents: read` its jobs need and GitHub rejected the whole workflow file at parse time. -
-
v0.3.2
bc6ee06c · ·v0.3.2 Fixes CI delivery and makes the production integration harness wait for the actual ready endpoint. - Publishes multi-architecture Docker images after code checks pass, then publishes the ClawHub skill after the image build. - Removes race instrumentation from Peen test targets and sets the project coverage floor to 80 percent, matching the full suite's measured coverage. - Waits for the production container's `/ready` endpoint instead of a startup log line, and gives failed test setup its own bounded cleanup context. - Links the user docs to the upstream libraries that provide provider drivers, streaming, HTTP and WebSocket transport, lifecycle, configuration, logging, storage, and metrics.
-
v0.3.1
196cad11 · ·v0.3.1 Documentation now describes Peen directly instead of the framework it started from. - Moves the user guides to `docs/` and removes the redundant `docs/peen/` directory. - Replaces the old Servicepack onboarding, architecture, lifecycle, and update material with Peen setup, architecture, and development guidance. - Keeps Servicepack as a short upstream reference for its process lifecycle plumbing.
-
v0.3.0
16cd66e3 · ·v0.3.0 WebSocket is now Peen's only agent-turn transport. REST remains for durable session reads and control operations. - Breaking: Removed `POST /v1/messages` and HTTP Server-Sent Events. Send `message.send` over `GET /v1/ws?sessionId=<uuid>` instead. A session UUID is created atomically from the first accepted message, and all connections for that session receive the same native agent events. - REST never creates or submits agent turns. It still lists durable messages, session state, events, jobs, and child-agent runs, and provides cancellation and external session-event control. - Updated aichteeteapee to v1.14.0 and regenerated the vendored dependency tree.
-
v0.2.0
42bc940f · ·v0.2.0 Adds a synchronized WebSocket session interface and moves the HTTP server to Serbewr. - Adds `GET /v1/ws?sessionId=<uuid>` for synchronized session clients. Browser clients authenticate with a WebSocket subprotocol, and connections in the same session receive the same agent events. - Replaces Echo with aichteeteapee Serbewr and WShub while retaining the existing JSON, Server-Sent Events, session, event, job, and child-agent API contracts. - Updates the API runtime and vendored dependencies, removing the unused Echo stack.
-
v0.1.0
11c8aff7 · ·v0.1.0 Initial release of Peen, a stateful coding-agent service. - Exposes durable agent turns, queued user messages, cancellation, job control, child agents, and both JSON and Server-Sent Events over the HTTP API. - Resolves workspace instructions, Agent Skills, named agents, events, and additive lifecycle hooks from the configuration and workspace layers. - Provides safe file tools that require a current-turn content read before a mutation and publish new files without replacing existing paths. - Supports OpenAI-compatible, Anthropic-compatible, and Z.ai Coding providers, including thinking streams across tool rounds. - Adds structured audit logs, a loopback metrics listener, built-in planning and freshness skills, and live end-to-end harness coverage. - Updates runtime and test dependencies to patched releases, including Kin OpenAPI, Echo, Moby archive, x/crypto, x/mod, Elelem, and Essesey.