Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
116 commits
Select commit Hold shift + click to select a range
30898f6
Fix ER lifecycle: force-kill orphans, concurrent shutdown, bound ER s…
Aksem Jul 21, 2026
20e48d1
Add OTLP endpoint validation, reachability probe, and export-log sile…
Aksem Jul 21, 2026
a599b21
Add automated release sweep across workspace packages (PRD-0006)
Aksem Jul 22, 2026
df006e1
Add list_envs/remove_envs actions and throttle run fan-out at depth 0…
Aksem Jul 23, 2026
91d8717
Split package release from workspace orchestration (ADR-0065)
Aksem Jul 23, 2026
c054de2
Sync python interpreters
Aksem Jul 23, 2026
a8cff6f
Add service config env-var overrides addressed by derived name (ADR-0…
Aksem Aug 1, 2026
0510524
Bridge check_toolchains drift into audit_code and fix precommit merge
Aksem Aug 1, 2026
29e58d6
Split file read from modify and add version-checked saves (ADR-0071)
Aksem Aug 3, 2026
e882c5b
Bound LSP request concurrency per backend (opt-in, unbounded by default)
Aksem Aug 4, 2026
983f26f
Apply formatter across the codebase
Aksem Aug 4, 2026
2c16b58
Make import sorting independent of the runner's working directory
Aksem Aug 4, 2026
224e648
Apply formatter to the remaining files
Aksem Aug 4, 2026
f5d6e13
Fix WM server layered-architecture violations found by audit_code
Aksem Aug 5, 2026
42f3330
Derive Python tool target-version from requires-python
Aksem Aug 6, 2026
fbdf049
Add in-session recovery from stale state (PRD-0008)
Aksem Aug 8, 2026
1deb3f3
Add code action resolve/apply and lint fix apply actions
Aksem Aug 8, 2026
889c0e9
Complete ADR-0080 cancellable in-flight runs, catch up recovery docs
Aksem Aug 8, 2026
9603bb9
Fix ruff position offsets and lint fixability, scope file listing to …
Aksem Aug 9, 2026
7334b82
Lint codebase and fix part of problems
Aksem Aug 9, 2026
d616913
Extract finecode_knowledge as a standalone schema-free package
Aksem Aug 9, 2026
329e087
Add node.js 22 to devcontainer
Aksem Aug 10, 2026
e5705ea
Absolutize resource URIs in CLI payloads before they reach ERs
Aksem Aug 10, 2026
7bfeed8
Lint fixes
Aksem Aug 12, 2026
f937d87
Name the unknown project when ER dispatch fans out to a bad path
Aksem Aug 12, 2026
8e315cb
Lint fixes
Aksem Aug 13, 2026
f81aab6
Stream subprocess output line by line and fix a semaphore leak
Aksem Aug 13, 2026
587603a
Add a keep-alive shared WM server for the devcontainer
Aksem Aug 15, 2026
9f2b4ab
Add run_agent_task action with pi.dev and Claude Code backends
Aksem Aug 15, 2026
54fd453
Add get_git_status, get_git_diff and restore_git_files actions
Aksem Aug 15, 2026
50a01e0
Add , , to icommandrunner
Aksem Aug 16, 2026
d39179b
Add --results-file to run for per-run, unmerged results
Aksem Aug 16, 2026
3439ae8
Lint fixes in finecode_extension_runner
Aksem Aug 16, 2026
4962590
Let a handler ask the run's client a question (ADR-0082)
Aksem Aug 17, 2026
b3fdd60
Replace elicitation origin ContextVar with an explicit parameter
Aksem Aug 17, 2026
eab535f
Add create/rename/delete file operations to code actions (ADR-0083)
Aksem Aug 21, 2026
d8cc237
Validate CLI payload field names and types against action schemas
Aksem Aug 22, 2026
0dbb9e2
Catch up action reference docs and fix converter edge cases
Aksem Aug 23, 2026
c0f9fc4
Replace layered concurrency caps with a single process budget (ADR-0090)
Aksem Sep 3, 2026
3ba945a
Add the WM-side knowledge service and a lookup-literal lint rule (ADR…
Aksem Sep 5, 2026
1334b61
Capture stderr from the dedicated WM server startup
Aksem Sep 5, 2026
10a13ec
Make the dev_workspace venv validity check actually exercise imports
Aksem Sep 5, 2026
f1e8a1b
Revert "Make the dev_workspace venv validity check actually exercise …
Aksem Sep 5, 2026
a7e490e
Add a real `finecode version` command; use it for venv validation
Aksem Sep 5, 2026
86e6b39
Wire root pyproject.toml up to already-landed extensions and contracts
Aksem Sep 5, 2026
081fbba
Add workspace extras selection for optional presets and dependencies
Aksem Sep 8, 2026
f4d6adb
Add fine_dep_graph preset and fine_dep_graph_falkordb extension
Aksem Sep 8, 2026
df87535
Add an audit-private CI job for the two private repos
Aksem Sep 9, 2026
65c5c07
Extend audit-private CI job with inspect_code and run_tests
Aksem Sep 10, 2026
c37d9af
Fix strict structure hooks to reconstruct enum-typed fields
Aksem Sep 10, 2026
c57f66b
Make finecode_knowledge an optional extra
Aksem Sep 11, 2026
38ba692
Update pyrefly from 1.2.* to 1.3.*
Aksem Sep 11, 2026
5f15030
Skip .uv-cache in project discovery
Aksem Sep 11, 2026
9005ab7
Update black to 26.3.1+ (security issue)
Aksem Sep 11, 2026
e7a51b6
Split the subprocess budget into startup and work halves (ADR-0093, A…
Aksem Sep 12, 2026
b5b9496
Save CI venv caches even when later steps fail
Aksem Sep 12, 2026
d3c8566
Add a handler to install pi packages into a project's own .pi/
Aksem Sep 12, 2026
51282d7
Reuse the restore step's cache key when saving CI venv caches
Aksem Sep 12, 2026
163acdc
Stop capping workspace fan-out width, narrow inspect_code bridge disp…
Aksem Sep 12, 2026
11291d2
Filter matrixed handlers by env and make CLI payload schema fetch rel…
Aksem Sep 13, 2026
8acfac4
finecode_knowledge is required dependency now. it was mistakenly
Aksem Sep 13, 2026
ac1f88b
Add start_runners to get_payload_schemas in wm_client
Aksem Sep 13, 2026
78ff2d6
Add wheel install mode for workspace packages, split build_artifact b…
Aksem Sep 13, 2026
73c0213
Stop ER-startup leaks and thread-pool exhaustion (ADR-0097)
Aksem Sep 14, 2026
0622da2
Format codebase
Aksem Sep 14, 2026
73ceab7
Add py-spy to dev_workspace for profiling a stalled WM
Aksem Sep 14, 2026
99bafc0
Persist uv's package cache across CI runs on the venvs filesystem
Aksem Sep 14, 2026
3ae0293
Bound ER control-plane RPCs and reap dead-channel runners (issue #12)
Aksem Sep 15, 2026
4bd334f
Add coverage signal for dispatch inputs no subaction covers (issue #1…
Aksem Sep 17, 2026
d622aa2
Format the config dump through the project's formatter
Aksem Sep 17, 2026
e9806b9
Sync watched files before pyrefly checks, drop the per-file cache
Aksem Sep 17, 2026
baaeab8
Replace isort with ruff's own import organizing in format_python_file
Aksem Sep 18, 2026
8a2f5bd
Add shared contract-test base classes for dispatch and format_file ha…
Aksem Sep 18, 2026
8f06d20
Reformat codebase
Aksem Sep 18, 2026
a78a009
Add profile and structured output to run_agent_task (PRD-0005 R3)
Aksem Sep 19, 2026
835f8ba
Stop partial-result streaming from double-merging sent results
Aksem Sep 20, 2026
611bd97
Add task_support helpers for typed agent task actions
Aksem Sep 20, 2026
a67a25d
Stop uv env handlers from dumping config through the formatter
Aksem Sep 21, 2026
fb2efd4
Tolerate EPERM from killpg during teardown and use psutil in e2e tests
Aksem Sep 21, 2026
e17453a
Update runner images in CI. Temporary ignore errors in inspect code step
Aksem Sep 22, 2026
dd4186c
Skip pytest spawn when nothing is collectable; dedupe handlerless-act…
Aksem Sep 22, 2026
5a03ca7
Spawn server processes from argv directly, no shell in between
Aksem Sep 22, 2026
c6c5507
Remove CI workflow tests
Aksem Sep 22, 2026
2948775
Quote install command args for cmd.exe and use RFC 8089 file URIs
Aksem Sep 22, 2026
a42291a
Answer workspace/workspaceFolders regardless of client capability
Aksem Sep 22, 2026
e65e7a6
Format codebase
Aksem Sep 22, 2026
b57db99
Run ICommandRunner commands as argv vectors, no shell
Aksem Sep 23, 2026
1edf7d5
Hold the ER startup slot until RUNNING, yielding on back-channel wait…
Aksem Sep 23, 2026
f7fa6cd
Snapshot spawned server processes with psutil on every platform
Aksem Sep 24, 2026
68866c7
Add stop-wm command to shut down the shared workspace server
Aksem Sep 24, 2026
1d2fd81
Name the real exception in TaskGroup failure summaries
Aksem Sep 24, 2026
b594825
Read and write text files as explicit UTF-8
Aksem Sep 24, 2026
32c6676
Start only selected matrix interpreters and repair crashed runners
Aksem Sep 24, 2026
e7caa9a
Upload FineCode logs in CI as artifacts
Aksem Sep 24, 2026
9f1e0fb
Format codebase
Aksem Sep 24, 2026
3edc8b9
Make streaming and git handler tests pass on Windows
Aksem Sep 25, 2026
1c351e6
Format the setuptools_scm version file after it is written
Aksem Sep 25, 2026
6d39903
Raise CI job budget and bound each slow step separately
Aksem Sep 25, 2026
4c12a10
Resolve projects on demand instead of at add_dir time (ADR-0101)
Aksem Sep 27, 2026
74d33b8
Make command runner and tests behave correctly on Windows
Aksem Sep 27, 2026
d65be4f
Raise CI install step timeout to 120 minutes
Aksem Sep 27, 2026
704b6eb
Move internal docs in a single workspace root
Aksem Sep 29, 2026
3fc2cce
Fix docs references
Aksem Sep 29, 2026
d12bb33
Merge branch 'chore/internal-docs-inside-root' into fix/lsp-request-c…
Aksem Sep 29, 2026
abe704b
Track root .ignore and document private-repo clone location
Aksem Sep 29, 2026
a4d68fc
Merge branch 'chore/internal-docs-inside-root' into fix/lsp-request-c…
Aksem Sep 29, 2026
494b2b8
Fix imports in wm server api handlers
Aksem Sep 29, 2026
3ffe0e3
Lease process-budget work slots per unit of work, not per run (ADR-0090)
Aksem Sep 30, 2026
8964036
Format code
Aksem Sep 30, 2026
0352090
Add resource-usage snapshot, CLI reporter and peak tracking
Aksem Oct 1, 2026
2e32a89
Make prepare-envs --env filter cover create_envs and install_envs alike
Aksem Oct 2, 2026
9bb23ac
Split matrix selection: run takes --interpreter, prepare-envs takes -…
Aksem Oct 3, 2026
945f6e3
Advance the resource-usage tick grid when a poll starts, not when it …
Aksem Oct 3, 2026
c9a7026
Report host memory pressure in resource-usage lines and run failures
Aksem Oct 3, 2026
1158a25
Add PyreflyConfig service to set pyrefly error-kind severities
Aksem Oct 4, 2026
ddabd2a
Drop the per-env config dump from uv install_deps_in_env
Aksem Oct 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
60 changes: 51 additions & 9 deletions .devcontainer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ This directory contains the DevContainer configuration for developing FineCode i
- `devcontainer.json`: Main configuration file for VS Code DevContainers.
- `docker-compose.devcontainer.yml`: Compose service definition for the main workspace container.

## Node.js

Node.js 22 is a runtime dependency of `setup_system` handlers that install
npm-distributed tools (e.g. pi coding agent, which rejects Node older than
22.19.0). The base image already ships `nvm` itself (no Node version installed), so
`setup-node.sh` installs Node 22 through that pre-existing `nvm` in
`postCreateCommand`. Because Node is installed via nvm under
the `vscode` user, `npm install -g` works without sudo.

## Local observability stack (opt-in)

The devcontainer includes the repository-level `docker-compose.otel.yml`, but all of
Expand All @@ -22,18 +31,51 @@ Bring the stack up either way:

WAL events are recorded on disk regardless of whether the stack is running, so you can
bring it up later and ingest the history retroactively. See
[ADR-0052](../../finecode_internal_docs/adr/0052-observability-stack-opt-in-via-compose-profile.md).
[ADR-0052](../finecode_internal_docs/adr/0052-observability-stack-opt-in-via-compose-profile.md).

## Persistent WM server

`FINECODE_WM_AUTOSTART=1` is set in `.env.example`, so `postStartCommand` runs
`start-wm-server --detach --keep-alive` on every container start, via
`start-wm-server.sh`. The workspace stays warm across commands instead of rebuilding
its config and runners each time. Comment the variable out to go back to a server
per client; the script is also a no-op when the `dev_workspace` venv does not exist
yet.

Changing the variable needs the container **recreated**, not reopened — Compose
resolves `.env` into a container's environment only when that container is created
(the same caveat as `FINECODE_OTLP_ENDPOINT` above; see [Developing
FineCode](../docs/guides/developing-finecode.md#local-observability-stack) for the
rebuild commands).

What comes with a keep-alive server — resident extension runners, a fixed log level,
and why a server started lazily after a crash is not one — is described under
[`start-wm-server`](../docs/cli.md#start-wm-server). Re-run
`sh .devcontainer/start-wm-server.sh` to get the persistent one back.

## Profiling the WM with py-spy

## Optional private internal docs mount
When the WM looks stalled, `py-spy` shows what its threads are doing without
restarting it or changing its code. It lives in the root `dev_workspace` group, so
it is at `.venvs/dev_workspace/bin/py-spy` after `prepare-envs --env=dev_workspace`
(or `scripts/setup-dev-workspace.sh`).

The workspace service supports an optional bind mount for private internal docs.
Use `sudo`: Yama's `ptrace_scope=1` lets a process attach only to its own
children, and the `vscode` user has no effective caps even with `SYS_PTRACE` in the
container's bound set. `sudo` also resets `PATH`, so invoke the binary by path from
the repo root.

- Container target path: `/workspaces/internal-docs`
- Host source path: `${FINECODE_INTERNAL_DOCS_PATH}`
- Fallback when unset: `./.devcontainer/empty-internal-docs`
```bash
# find the pid — a dedicated WM, or the shared keep-alive one
pgrep -f 'start-wm-server --port-file'
pgrep -f 'start-wm-server.*--keep-alive'

This means developers without private docs access can still start the devcontainer successfully.
# one stack dump per thread
sudo .venvs/dev_workspace/bin/py-spy dump --pid "$PID"

The mount is writable from inside the container so you can edit docs directly.
# a 90-second flame graph
sudo .venvs/dev_workspace/bin/py-spy record --pid "$PID" --duration 90 --output wm-profile.svg
```

If you have private docs locally, set `FINECODE_INTERNAL_DOCS_PATH` in your shell or a local `.env` file before opening the devcontainer.
`--subprocesses` is deliberately left off: it would fold every Extension Runner into
the WM's flame graph. Profile an ER separately by pointing `--pid` at it.
23 changes: 22 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,28 @@
],
"service": "workspace",
"shutdownAction": "stopCompose",
"postCreateCommand": "sh .devcontainer/post-create-dev-workspace.sh && sh .devcontainer/setup-shell.sh",
// Node.js is required by the pi coding agent, which setup_system installs via
// npm. Pi's preflight rejects anything older than 22.19.0, so Debian's own
// nodejs package is not an option, and so is the node devcontainer feature: the
// base image already ships nvm itself, and running the feature on top of that
// hits a BuildKit bug writing into nvm's cache dir. setup-node.sh installs Node
// via that pre-existing nvm instead, at container-create time. See
// setup-node.sh for the full explanation.
// remoteEnv (not containerEnv): containerEnv is baked into the compose
// service's own environment, including its `sleep infinity` entrypoint process —
// and "${containerEnv:PATH}" does not self-resolve there, so it overwrote PATH
// with the literal unexpanded string and broke everything, including `sleep`.
// remoteEnv only applies to devcontainer-managed processes (postCreateCommand,
// terminals), where the substitution does work.
"remoteEnv": {
"NVM_DIR": "/usr/local/share/nvm",
"PATH": "/usr/local/share/nvm/current/bin:${containerEnv:PATH}"
},
"postCreateCommand": "sh .devcontainer/setup-node.sh && sh .devcontainer/post-create-dev-workspace.sh && sh .devcontainer/setup-shell.sh",
// postStart, not postCreate: a stopped container loses its WM server, so this
// has to run again on every start. The venv it needs may not exist yet on the
// first create; the script exits cleanly in that case.
"postStartCommand": "sh .devcontainer/start-wm-server.sh",
"customizations": {
"vscode": {
"extensions": [
Expand Down
10 changes: 7 additions & 3 deletions .devcontainer/docker-compose.devcontainer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ services:
image: mcr.microsoft.com/devcontainers/python:3.14
init: true
user: vscode
# py-spy needs ptrace/process_vm_readv; Docker's default seccomp profile
# allows them only with SYS_PTRACE. The devcontainer is dev-only; CI does
# not use this compose file.
cap_add: [SYS_PTRACE]
working_dir: /workspaces/finecode
command: sleep infinity
environment:
Expand All @@ -11,6 +15,9 @@ services:
# both COMPOSE_PROFILES=otel and FINECODE_OTLP_ENDPOINT in .env — the ready
# collector URL is provided there, so developers never compose it themselves.
- FINECODE_OTLP_ENDPOINT=${FINECODE_OTLP_ENDPOINT:-}
# Read only by .devcontainer/start-wm-server.sh; passed through here so the
# value set in .env is visible to processes inside the container.
- FINECODE_WM_AUTOSTART=${FINECODE_WM_AUTOSTART:-}
# uv's default cache (~/.cache/uv) lives on the container's overlay
# filesystem, a different device than this bind-mounted workspace. uv
# dedupes installs by hardlinking from its cache into each venv, but
Expand All @@ -21,9 +28,6 @@ services:
volumes:
- .:/workspaces/finecode:cached
- ./.claude:/home/vscode/.claude:cached
- type: bind
source: ${DEVCONTAINER_INTERNAL_DOCS_PATH:-./.devcontainer/empty-internal-docs}
target: /workspaces/finecode_internal_docs
networks:
- finecode-net
depends_on:
Expand Down
24 changes: 24 additions & 0 deletions .devcontainer/setup-node.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/bin/sh
# Installs Node via the nvm already baked into the base image.
#
# We do NOT use the ghcr.io/devcontainers/features/node feature for this:
# the base image already ships nvm itself (no Node version installed yet)
# at /usr/local/share/nvm, owned by vscode:nvm. Running the node feature on
# top of that hits its "NVM already installed" code path, which skips the
# ownership fixup it only does for a freshly created nvm dir and calls
# `nvm install` directly. That specific command works fine under a normal
# `docker run`, but fails with "Permission denied" writing into
# /usr/local/share/nvm/.cache when run inside a BuildKit RUN layer, which
# does not reproduce ownership from the base image's read-only layer
# correctly on copy-up. Running nvm install here, in postCreateCommand
# (a normal container process, not a build layer) sidesteps the bug.
set -eu

export NVM_DIR="/usr/local/share/nvm"
export NVM_SYMLINK_CURRENT=true
# shellcheck source=/dev/null
. "$NVM_DIR/nvm.sh"

umask 0002
nvm install 22
nvm alias default 22
29 changes: 29 additions & 0 deletions .devcontainer/start-wm-server.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/sh
# Start a persistent shared FineCode WM server at container start, so the
# workspace stays warm for the life of the container. What that costs is
# documented in docs/cli.md, "Autostarting a persistent server".
#
# FineCode itself never reads FINECODE_WM_AUTOSTART — this script is its only
# consumer, and it turns it into an explicit `--keep-alive` on the server it
# starts, because keep-alive must never be ambient.
set -eu

if [ -z "${FINECODE_WM_AUTOSTART:-}" ] || [ "${FINECODE_WM_AUTOSTART}" = "0" ]; then
exit 0
fi

VENV_PYTHON=".venvs/dev_workspace/bin/python"
if [ ! -x "$VENV_PYTHON" ]; then
echo "FineCode WM autostart: $VENV_PYTHON not found, skipping." >&2
exit 0
fi

# Never fatal: the workspace is fully usable without it, because every client
# starts a server on demand anyway. Failing container start over a warm cache
# would be a worse outcome than the cold start it is trying to avoid.
if "$VENV_PYTHON" -m finecode start-wm-server --detach --keep-alive; then
echo "FineCode WM autostart: shared server running."
else
echo "FineCode WM autostart: no shared server reachable yet; it may still be" \
"starting, and clients attach to it when it is." >&2
fi
10 changes: 6 additions & 4 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
# Local developer environment variables.
# Copy values you need into .env for your machine.

# Optional: absolute or repo-relative host path to private internal docs.
# When unset, devcontainer falls back to ./.devcontainer/empty-internal-docs.
DEVCONTAINER_INTERNAL_DOCS_PATH=

# Optional: local observability stack (grafana/otel-lgtm, bundling the OTel
# Collector, Tempo, Prometheus, Loki, and Grafana, plus a standalone Jaeger).
# These services are gated behind the "otel" Compose profile and stay DOWN by
Expand All @@ -20,3 +16,9 @@ DEVCONTAINER_INTERNAL_DOCS_PATH=
# use it to start/stop the collector while the endpoint stays armed.
# COMPOSE_PROFILES=otel
# FINECODE_OTLP_ENDPOINT=http://otel-lgtm:4317

# Start a persistent shared WM server when the devcontainer starts, so config and
# extension runners survive between commands. Comment out to get a server per
# client instead. What comes with it: docs/cli.md, "Autostarting a persistent
# server".
FINECODE_WM_AUTOSTART=1
12 changes: 12 additions & 0 deletions .github/ci/finecode-user.ci.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# CI counterpart to a developer's gitignored finecode-user.toml.
#
# The `.ci` infix is load-bearing: .gitignore ignores the unanchored name
# `finecode-user.toml` at any depth, so a file here named exactly
# `finecode-user.toml` could never be committed. This name is not ignored, which
# is what lets the public repo track the CI copy while the developer copy stays
# out of git. Do not "tidy" the infix away.

presets = [{ source = "fine_knowledge" }]

[dependency-groups]
dev_workspace = ["fine_knowledge~=0.1.0a0"]
Loading
Loading