115 Commits
Author SHA1 Message Date
Pranit a7ad972621 Encode inline fuzz seeds the way the tests read them
A fuzz test reads its input through std.testing.Smith, which reads a slice
as a little-endian u32 length and then that many bytes. The inline seeds of
the older fuzz tests were plain strings, so each lost its first four bytes
to the length: "one" replayed as an empty input, and "split every field"
read "spli" as a length. The fx tests now wrap their seeds in
fuzz_seed.slices, which writes that length first. The session manager
imports nothing from fx, so its two targets keep their seeds as saved
inputs in tests/fuzz/corpus.
2026-10-22 18:44:46 -04:00
Pranit 2e9a945fb9 Note which sanitizer test failures are timing 2026-10-22 11:52:55 -04:00
Pranit 37e79dcdd5 Add a nightly ThreadSanitizer run of the unit tests 2026-10-22 11:52:55 -04:00
Pranit 7ae4d4107b Add a fuzz build step, nightly fuzzing, and shell parity tests
- `zig build fuzz` builds only the fuzz tests listed in `tests/fuzz/targets.json`. `-Dfuzz-target=<name>` picks one target, and `--fuzz=N` searches for new failing inputs.
- `zig build test` replays each target's saved inputs from `tests/fuzz/corpus/<target>/` on every pull request.
- A nightly Fuzz workflow fuzzes every target for about 20 minutes, uploads any failing input, and opens or updates an issue for that target. A pull request that changes the fuzzing setup fuzzes each target for two minutes.
- The shell parity tests run every command form fx runs without review through sh, dash, bash, and zsh, with and without `extendedglob`, and check that each one runs exactly as fx parsed it. The `shell_parity` target checks generated commands the same way.
2026-10-22 11:52:23 -04:00
Pranit 73b9704036 Bring the remaining fx TLA+ models into tests/tla
- Add models, checkers, and Bun drivers for ACP permission modes and
  speed, launch flags, durable libfx, the MCP-v2 engine and the MCP
  host, /usage, the shell tool and git admission, the shell snapshot
  and terminal lifecycle, the libfx provider credential edge, the
  indexer's grep, file picker, and snapshot reuse, and the session
  rollout.
- Add tests/tla/lib/ and tests/tla/drivers/lib/ so every checker and
  driver finds TLC and Java the same way, gives each TLC run its own
  temp folder, runs the binary from this checkout, and keeps sound off.
- Add tests/tla/mcp/rules.md, the MCP specification rules the MCP-v2
  models cite by ID.
- Mark the models that describe the next MCP-v2 version, and run their
  drivers only with --next or FX_TLA_NEXT_MCP=1.
- Point the /usage and MCP trace comments in src/ at their models, and
  update tests/tla/README.md, tests/AGENTS.md, and CONTRIBUTING.md.
2026-10-14 01:24:13 -04:00
Pranit 9534bf74d2 Move the TLA+ Bun drivers into tests/tla/drivers
- Move `drive.mjs`, `drive-agents.mjs`, `agent-process.mjs`, and
  `graph.mjs` from `tests/tla/sdk/` to `tests/tla/drivers/`. They read the
  state graphs that `tests/tla/sdk/check.sh` writes.
- Point CI, `AGENTS.md`, `sdk/AGENTS.md`, and the `tests/tla` notes at the
  new paths.
2026-10-13 20:46:43 -04:00
Pranit 542f00bd37 Keep every TLA+ model under tests/tla
- Move the session manager specs, trace checkers and design record, the
  indexer refresh model, and the libfx durable session model and its Bun
  drivers into `tests/tla/`, so `src/` and `sdk/` hold no TLA+ files.
- Add `tests/tla/indexer/check.sh`, which runs every refresh config and
  requires its expected verdict.
- Point code comments, CI, `AGENTS.md`, `sdk/AGENTS.md`, and
  `CONTRIBUTING.md` at the new paths, and document the models in
  `tests/tla/README.md`.
2026-10-13 20:46:43 -04:00
Pranit bc51246646 Merge origin/main into fazxes/native-workspace-indexer 2026-10-12 17:51:07 -04:00
Pranit fc2cf2bd28 Stop counting the optional PR workflows
The guide said two more workflows run on a pull request, but the
Examples workflow and the Shell command overhead benchmark also
report. Name them as examples instead of giving a count, and say that
only the five required checks block a merge.
2026-10-12 05:36:04 -04:00
Pranit a1b7605ab1 Correct review findings in the contributing guide
Put commit signing before pushing, since pushing first leaves unsigned
commits to rewrite. Describe Startup Latency without a command count,
because the benchmark measures five fx commands plus a baseline, and
limit the Shellcheck row to the scripts the job lists. Say that a
validate-only release still uploads workflow artifacts but skips the
tag, GitHub Release, CDN, and update channel.

Register an E2E file in macos-platform-tests.json only when it
branches on the platform, and stop sending configuration changes to
CONTRIBUTING.md now that its configuration reference is gone. Tie the
companion docs PR in AGENTS.md to push access on the docs repository,
which organization membership alone doesn't grant.

In the README tree, list MCP under core/, where the default client
lives, and describe src/mcp/ as the opt-in v2 engine.
2026-10-12 05:25:06 -04:00
Pranit ff9c8b0a33 Ask outside contributors for exact manual changes
The fx.sh manual is built from a private repository, so outside
contributors can't edit it. Ask them to put the exact change each
affected page needs in a Docs section of the PR description. In
AGENTS.md, tell members of the vercel-labs organization to update the
manual in a companion pull request, and stop naming the private
repository in both files.
2026-10-12 04:37:31 -04:00
Pranit 635c05495e Describe repository access by maintainer role
Only maintainers can push branches, add labels, including ci:macos,
or start workflow runs. Say that directly instead of naming GitHub
access levels, and give the outside-contributor path at each of those
steps.
2026-10-12 04:29:03 -04:00
Pranit 00d6f5f973 Rewrite the contributing guide
CONTRIBUTING.md had grown into a product reference: MCP lifecycle
details, ACP extensions, the auto-mode review rules, and config keys,
most of which AGENTS.md and the fx.sh/docs manual already cover.
Rebuild it around the contribution workflow: setup, testing, pull
requests, labels, CI, docs, and releases. Every step that needs write
or triage access now says what an outside contributor can do.

Document that main accepts only signed commits, that an older Zig
fails inside build.zig with an error that doesn't name the version,
and how to try a change against an empty profile. Drop stale claims
about a sandbox project key, a tests/e2e/tapes directory, and a PGSO
local reproduction command.

In the README, draw the source tree with branch lines and keep fx ask
and fx acp on one line in the surface table.
2026-10-12 04:18:14 -04:00
Pranit 0a76c1ee38 Merge origin/main and port the indexer to Zig 0.17
main moved to Zig 0.17. The branch keeps its deletion of
file_index_cache.zig, ignored_dirs.zig and workspace_files.zig, whose
only changes on main were 0.17 renames, and keeps its own side of
grep_search.zig and glob_files.zig. AGENTS.md takes main's refresh plus
the indexer and safe git notes.

The branch's code moves to the 0.17 names: std.Io.Dir.path,
Allocator.print, std.mem.print, builtin.target and @backingInt. The
wildmatch test builds its repeated strings with a local helper because
the indexer cannot import text_utils, and two folder selection test
calls gain the try that 0.17 requires.
2026-10-12 02:20:21 -04:00
Pranit d93acc528d Merge pull request #1221 from vercel-labs/fazxes/scope-readme-updates
Keep feature docs out of the README
2026-10-12 01:07:23 -04:00
Pranit 977312439e Keep feature docs out of the README
AGENTS.md told agents to add feature descriptions and usage examples
to README.md for every user-facing change, so feature work kept growing
the README. Point those docs at --help and the fx.sh/docs manual
instead, say how to update the manual with or without access to
fx-web, and limit README edits to statements that become false or new
top-level capabilities.

Drop the release step that updated the README's install version, which
is no longer pinned, and point the CONTRIBUTING.md checklist at the
documentation rule.
2026-10-11 23:52:02 -04:00
Pranit 28fd1a00ed Merge origin/main into fazxes/native-workspace-indexer 2026-10-11 05:59:04 -04:00
Pranit eb5100b7f1 Merge remote-tracking branch 'origin/main' into fazxes/zig-0.17-upgrade
# Conflicts:
#	README.md
#	src/gateway/host_stream_provider.zig
2026-10-11 01:39:52 -04:00
Pranit b0c091f6ce Rewrite the README as a short introduction to fx
Lead with what fx is, its features, install, and a quick start, and
leave reference detail to fx.sh/docs. Point the custom model
connections link in CONTRIBUTING.md at the docs page, since the README
section is gone.
2026-10-10 18:17:22 -04:00
Pranit 8925f00b74 Add the native workspace indexer foundation
- Add src/core/indexer/, which reads gitignore rules, repository layout, and git config as files and never starts a process.
- Match git's ignore decisions for nested .gitignore files, info/exclude, and the global excludes file, including include and includeIf config.
- Report the filter drivers a repository's own config defines, and fail closed when that config cannot be read.
- Check in CI that outside code imports only indexer.zig and that the indexer imports nothing that can start a process.
2026-10-08 13:15:40 -04:00
Pranit b1d515851a Upgrade to Zig 0.17
Build fx with Zig 0.17.0. build.zig.zon requires it, every workflow
installs it, and PGSO qualification uses LLVM 22.1.8 to match.

Zig 0.17 removes `**`, `errdefer |err|`, `@cImport`, and the old type
info field lists. The source moves to `@splat`, a comptime
`text_utils.repeat` helper, split cleanup functions, and the new
field_names and field_types arrays. The Node-API addon translates
node_api.h with a build step. Test fakes checked with `@hasDecl` become
pub, because `@hasDecl` no longer sees private declarations.

`zig build test` gives the test binary its fx and source paths through
a generated test_paths module, since the build no longer exposes install
paths for environment variables.

Zig 0.17's SafeAllocator grows a small allocation in place only when it
sits at the end of a bucket, and buckets are never reused, so an
allocation-failure sweep could count a different number of allocations
on each run. Sweeps and allocation-count tests now use
testing_allocator.no_resize, which never resizes in place.

allocRemaining now treats its limit as inclusive. readFileToEnd keeps
rejecting a file of exactly max_bytes by reading through
appendRemaining. Direct allocRemaining callers for remote responses now
accept a body exactly at their limit.

Zig 0.17's memset stores a full vector per iteration, so the Linux
memset replacement is removed. macOS release binaries now require macOS
15, Zig 0.17's default minimum.
2026-10-05 19:44:53 -04:00
Pranit 4b0d1cafb4 Let outside contributors open PRs without a type label
Applying a label takes triage access and dispatching a workflow takes
write access, so contributors from outside the organization could not
follow the PR rules. AGENTS.md also told agents to hold such PRs in
draft until a maintainer added the label.

Keep the type label rule for contributors who can manage labels. For
outside contributors, a maintainer applies the label during review, and
they ask in the PR when they need the macOS checks, PGSO, or another
on-request run.
2026-10-05 17:39:20 -04:00
Pranit 3deb16329c Merge remote-tracking branch 'origin/main' into fazxes/linux-first-ci
# Conflicts:
#	CONTRIBUTING.md
2026-10-05 08:39:14 -04:00
Pranit 5126a07b3f Merge remote-tracking branch 'origin/main' into fazxes/linux-first-ci 2026-10-02 02:36:10 -04:00
Pranit f7ab78361a Draw the first frame before slow startup work
- Show the first frame before reading a Keychain-backed fx login or stored key on macOS. A prompt sent before the login loads waits for it, then sends.
- Load skills after the first frame. Skill menus fill in when the catalog lands, and skill discovery issues are reported then.
- Check the other sign-in sources after the first frame when a credential is already active, so a launch with an environment key no longer loads Security.framework before drawing.
- Wait at most 1 ms for input before drawing the first frame, instead of 8 ms.
- Stop waiting up to 200 ms for terminals that ignore the background color query. The startup probe now ends at the device attributes reply.
- Show "skills: loading" in the full-transcript session details while skills are still loading.
- Add benchmarks/first_frame.py to measure time to the first frame and compare builds under the same load.
2026-10-01 23:46:05 -04:00
Pranit f80232a0aa Detect E2E helpers that read the platform through node:os
The shard guard treats platform() from node:os as a platform branch, but
the detector only matched process.platform, so a helper written that way
could skip macOS. Match both, list the helper rule in the detector's
header, and say "reads the platform" in the docs.
2026-10-01 17:35:27 -04:00
Pranit 043436148f Fix the macOS dispatch fetch depth and detect platform E2E helpers
The dispatch fetch depth used `event == dispatch && 0 || 2`. Expressions
treat 0 as falsy, so every event got depth 2, origin/main was never
fetched, and a manual dispatch failed at detect. Put the dispatch case
last so it evaluates to 0, and capture the merge base before calling
the detector so a missing base fails with git's own error.

The detector ignored shared E2E helpers, so a change to a platform
branch in tests/e2e/tmux-helpers.ts could skip macOS. Treat a helper
that reads process.platform on either side of the change as a macOS
input.
2026-10-01 16:39:29 -04:00
Pranit d943ad4e9d Check the Zig cache path and diff macOS dispatches against main
A manual macOS dispatch now compares the branch with its merge base on
main, so it runs at least the checks its pull request run would and
cannot replace a native addon failure with a weaker pass.

The setup-zig action fails if setup-zig stops pointing the Zig cache at
the workspace directory the cache steps save and restore.

The docs now say that Binary Size smoke-tests every target, that the
platform list covers darwin and linux branches, and that only the Linux
Zig cache actions skip saving on pull requests.
2026-10-01 15:39:49 -04:00
Pranit 539ca4650b Merge main and refine Ultrafast indicators 2026-10-01 14:28:00 -04:00
Pranit ebba84f05e Close macOS detection gaps and stop pull requests saving Zig caches
The macOS detector now fails the check when it cannot read either
revision or the platform test list, instead of reporting that macOS is
not needed. It also treats Linux and BSD code paths as platform code,
because macOS takes the other side of a Linux branch. Windows-only
branches still skip macOS. Replaying the last 150 commits on main moves
macOS runs from 72 to 76.

The macOS platform E2E files now run in two weighted shards that share
one baseline-CPU build. tui-performance and tui-resume join the list
because they branch on the platform.

Linux Zig jobs restore a cache keyed by the Zig version and build files,
and only runs on main save it. Pull request runs no longer add cache
entries that push main's out of the quota. The macOS jobs never run on
main, so their Zig cache is off.

Build & Test now also requires the SDK jobs, which Publish libfx relies
on. Manual dispatches get their own concurrency group so they cannot
cancel the push run on main. The N-API build pins Node 24, Binary Size
smoke-tests every target, and the shellcheck job syntax-checks each
script instead of only the first.
2026-10-01 14:02:22 -04:00
Pranit 88cd75ba64 Merge remote-tracking branch 'origin/main' into fazxes/linux-first-ci
# Conflicts:
#	.github/workflows/ci.yml
#	.github/workflows/full-ci.yml
#	AGENTS.md
#	CONTRIBUTING.md
2026-10-01 05:17:16 -04:00
Pranit c6b629ead8 Gate CI on Linux and run macOS only when a change needs it
- Run the full deterministic E2E suite on Linux in four shards on every pull request, plus the MCP conformance baseline, all against one shared build of fx.
- Run macOS arm64 unit tests and platform E2E files only when a change touches macOS-specific code, build.zig, macOS signing, or the native SDK addon, or carries the ci:macos label. Otherwise the macOS arm64 check passes without a macOS runner.
- Remove the four-platform Full CI workflow and the separate cross-target compile jobs.
- Smoke-test the Linux arm64, macOS x86_64, and macOS arm64 binaries in Binary Size, and reuse the base build for later pushes to the same pull request.
- Build the SDK WASM surfaces and Node-API addons once and share them across the SDK test jobs.
- Run PGSO on pull requests only when the PGSO pipeline changes, and keep release PGSO evidence for 90 days.
- Run the long-turn memory, libfx runtime, and live ACP jobs only on request.
- Limit libfx publishing to an archive check, an install smoke test, and a registry byte comparison.
- Add a warning when an E2E file passes only on retry.
- Remove the unused Prepare Release workflow and document the new CI rules.
2026-10-01 05:12:19 -04:00
Pranit 110823f201 Add opt-in Ultrafast mode 2026-10-01 03:54:09 -04:00
Pranit ff7ed7e849 Merge main into simple-compaction 2026-10-01 02:54:29 -04:00
Pranit d9f776634f Merge pull request #1094 from vercel-labs/fazxes/acp-embedder-gaps
Close ACP gaps for embedded clients
2026-09-30 17:10:46 -04:00
Pranit c6661e8eb6 Merge pull request #1098 from vercel-labs/b/technical-writer-skill
Add the technical-writer skill for repository prose
2026-09-29 18:07:51 -04:00
Pranit 6222b8e42d Merge remote-tracking branch 'origin/main' into fazxes/compaction-timeline
# Conflicts:
#	AGENTS.md
#	CONTRIBUTING.md
#	src/core/config/config_runtime.zig
2026-09-29 18:03:09 -04:00
Ben Sabic 9bbb4f8c3e Add the technical-writer skill for repository prose
Add the technical-writer skill under .fx/skills and require it for prose
in AGENTS.md, CONTRIBUTING.md, and the issue form.
2026-09-29 21:12:41 +10:00
Matan Kushner 0edec72bdf Allow skill symlink authorities in profile settings 2026-09-29 14:11:22 +09:00
Pranit b8ae92124d Close ACP gaps for embedded clients
- Keep tools from MCP servers the client supplies loaded on every turn. A server entry can opt out with `_meta.fx.alwaysLoaded: false`.
- Run a model call to a live MCP tool that is not loaded yet through the normal MCP permission path instead of rejecting it.
- Accept a `session/prompt` with `_meta.fx.steer` while a turn is running. The turn picks it up at its next safe point, echoes it as a `user_message_chunk`, and answers it with `absorbed`, or `cancelled` with `dropped` when the turn is cancelled.
- Accept `systemPrompt` text blocks on `session/new` in append mode, advertise `sessionCapabilities.systemPrompt`, reject invalid blocks with `-32602`, and restore the prompt on `session/load` and `session/resume`.
- Leave out terminal-specific instructions when `initialize` sets `_meta.fx.terminal: false`.
- Mark discovery calls such as `capability_search`, `mcp_select_tool`, and `read_tool_result` with `_meta.fx.toolCall.internal`, and add the MCP server, original tool name, and server title to MCP tool calls.
- Serve MCP servers over the ACP connection through `type: "acp"` entries with a `serverId`, advertised as `mcpCapabilities.acp`. Unanswered `mcp/message` requests get `$/cancel_request` when the turn is cancelled or times out.
- Retry a client-hosted MCP server on the next turn when a cancelled turn interrupted its first connection.
- Use the `cwd` on `session/new`, `session/load`, and `session/resume` as the session workspace, and start project MCP servers in it.
- Include profile MCP servers from `~/.fx/mcp.json` in an ACP session only when it sets `_meta.fx.profileMcpServers`.
- Replay absorbed steering and MCP tool call titles and identity on `session/load`.
2026-09-29 00:00:33 -04:00
Pranit 4123ae2006 Replace context compaction with one compactor
- Manual /compact, automatic compaction, and context overflow recovery all run through src/core/compactor.
- User messages stay exact, the newest compacted turns keep their final replies word for word, and the rest of the assistant's work is summarized.
- Every compacted turn and tool call is saved unchanged as M1, M2, ... and T1, T2, ..., and read_tool_result opens and searches them.
- The summary uses the conversation's model at its lowest reasoning level, with one retry on another model family through the gateway.
- Automatic compaction starts at auto_compact_percent of usable input (10 to 80, default 80); FX_AUTO_COMPACT_PERCENT overrides it.
- Checkpoints written by the previous compactor still load.
- CI checks that code outside the compactor uses only its front door.
2026-09-26 21:45:26 -04:00
Pranit 031a5fdacd Report a server's failure only to a search that names it
- A search reports a failed server's reason only when its server field
  names that server. A free-text query that mentions a failed server gets
  its normal results again.
- Word the result as the server being unavailable, since the recorded
  reason is not always a startup failure.
- A deferred fx ask connection passes access and authority errors through
  instead of reporting the recorded failure.
2026-09-24 16:41:17 -04:00
Pranit 5e84f6e811 Tell the model why an MCP server failed to start
- Report the recorded startup failure when a tool search names a server
  that failed to start, including a deferred server in fx ask, instead of
  an empty result or a bare error name.
- Report it when a tool call finds its server stopped and the relaunch
  fails, instead of the bare error name.
2026-09-24 15:58:24 -04:00
Pranit f97b2b80c1 Reuse the UTF-8 boundary helper for the stderr tail
- Skip a partial character at the start of the retained stderr tail with the shared boundary helper, and test tails that begin inside a character.
- Fail the stdio diagnostics tests instead of crashing when a child has not been reaped.
- Rewrap the startup failure paragraph in CONTRIBUTING.md.
2026-09-23 23:15:51 -04:00
Pranit 91f19ac714 Pin the new startup error mappings with tests
- Fix the startup budget through the connection control, from the same instant as the deadline.
- Test that a write to a child that closed stdin fails as a closed connection with its exit details.
- Test that a stalled discovery probe followed by an exiting legacy launch keeps its startup restart.
- Document the detailed startup failure for servers that close their connection before answering `initialize`.
2026-09-23 22:54:02 -04:00
Pranit e2b38a90e8 Name the startup setting only when it set the timeout
- Report the smaller of the time left and `startup_timeout_ms` as the startup budget, and name `startup_timeout_ms` only when that setting set it.
- Keep the startup restart when a discovery probe timed out before a legacy launch closed its connection.
- Report a child that closed stdin before fx's request landed as a closed connection, with its exit and stderr.
- Pipe stderr in the stdio dispatcher's shell test helper, as the server launcher does.
- Document that startup exits are reported in detail when they happen before `initialize` is answered.
2026-09-23 22:25:04 -04:00
Pranit 1c7e44d88f Keep the startup restart for servers fx stops over bad output
- Restart a stdio server once when fx stopped it for invalid output during startup, and skip the restart only when the server closed its connection at every offered protocol version.
- Report the startup budget the connection had, including after a crash-recovery relaunch.
- Keep the specific startup failure after crash-recovery relaunches and deferred `fx ask` connections instead of replacing it with an error name.
- Fail pending requests as soon as a stdio server's connection ends.
- Escape control, bidi, and zero-width characters in server stderr with the shared terminal-safe encoder.
- Build the WASM surfaces, where process signals carry no number.
2026-09-23 21:49:56 -04:00
Pranit 2802a82831 Show why stdio MCP servers fail to start
- When a stdio MCP server exits during startup, report its exit code or signal and an excerpt of its stderr instead of `McpInitFailed`.
- Limit that excerpt to one line of at most 400 bytes covering the first and latest output, with secrets masked and terminal escape sequences removed.
- When startup times out, name the budget and the `startup_timeout_ms` key, plus the exit of an earlier launch if there was one.
- Stop restarting a stdio server during startup once it has exited at every offered protocol version or its startup deadline has passed.
- Show that same reason when a required MCP server fails to start and fx refuses to continue.
2026-09-23 21:07:57 -04:00
Pranit 399f2b87ac Open MCP list in the interactive menu
Route /mcp list through the existing Servers menu while preserving diagnostic output for noninteractive fx mcp list.
2026-09-22 14:59:43 -04:00
Pranit 571b65b98a Merge pull request #918 from samcx/codex/slack-cli-install
Install the Slack workspace bot through the CLI
2026-09-21 12:36:46 -04:00