Skip to content
Justin SilverTECHNOLOGY, TRAVEL & EVERYTHING IN BETWEEN
Libraries & Tools
Solidity development toolsSoliditymacOSLinuxWindows

forgeds

forgeds is my modified build of Foundry's Forge for viaIR coverage and development across AI agents' git worktrees. It adds source instrumentation, a compiler-result cache shared across checkouts, separate project output folders and quieter compiler warnings.

It accepts Forge commands and foundry.toml settings, with forgeds-specific output defaults and options described below.

Three source-code worktrees feed a shared compiler archive, with a probe leading to a coverage grid.

Release status

GitHub prerelease, build 4ca15fc, version 1.9.1-dev. The four platform builds and release job passed. Available binaries cover macOS Apple Silicon, Linux x86_64, Linux arm64 and Windows x86_64. There is no prebuilt Intel Mac binary in this release.

The release page has archives and matching .sha256 files. Names such as forgeds_darwin_arm64.tar.gz move to the newest build. Commit-named assets such as forgeds-4ca15fc_darwin_arm64.tar.gz pin a build. forgeds_latest.txt gives the commit served by the moving names.

Install a prebuilt binary

For macOS Apple Silicon, run these commands in an empty download directory. This example pins build 4ca15fc and checks its checksum before extracting. Add ~/.cargo/bin to PATH if it is not already there.

gh release download forgeds -R doublesharp/foundry \
  -p 'forgeds-4ca15fc_darwin_arm64.tar.gz*'
shasum -a 256 -c forgeds-4ca15fc_darwin_arm64.tar.gz.sha256
mkdir -p "$HOME/.cargo/bin"
tar -xzf forgeds-4ca15fc_darwin_arm64.tar.gz -C "$HOME/.cargo/bin" forgeds
forgeds --version

The full commit for this build is 4ca15fcba25aa61a1b436d28b428e30b459f3d56. Choose the corresponding platform archive on Linux or Windows and use that platform's SHA-256 tool. The source-install option is:

cargo install --locked --git https://github.com/doublesharp/foundry \
  --tag forgeds-4ca15fc forge --bin forgeds --features forgeds

Configure a project for agents

Set compiler_warnings in the project's existing foundry.toml profile. Add the two output folders to .gitignore. Keep the shared compiler cache enabled and avoid routine --force or clean builds, which discard the reuse you want.

[profile.default]
compiler_warnings = "changed"
# Add to .gitignore
forgeds-out/
forgeds-cache/

forgeds selects forgeds-out/ and forgeds-cache/ even when foundry.toml sets out or cache_path. Explicit FOUNDRY_OUT, FOUNDRY_CACHE_PATH, --out and --cache-path override those defaults. Use a separate output path for each worktree when redirecting artifacts to another disk.

Run tests and measure coverage

Use focused tests during edits, then measure coverage with the project's configured compiler. --report gaps adds a compact JSON list of uncovered items.

forgeds test --mt <test_name>
forgeds coverage --instrumented --report summary --report gaps
forgeds coverage --instrumented --report lcov

Instrumented coverage retains the optimizer and via_ir settings. It measures lines, statements, branches and functions, including branches in ?:, &&, || and inline assembly. Warnings refer to the original source.

Use // coverage ignore next immediately before code to omit, or // coverage ignore file for a whole source file. The forge coverage, istanbul and solidity-coverage comment forms are supported too.

The probes change bytecode and gas usage. Use normal builds for gas measurements and deployment checks. --report bytecode is unavailable in instrumented mode. An unchanged rerun can reuse compiled probes; any source edit still triggers a full instrumented compile.

Share compiler results across worktrees

The shared cache lives at ~/.foundry/cache/compilers and works with solc and Solar. Its key includes the compiler executable, full standard-JSON input and compiler arguments. Identical requests reuse complete compiler results while each project keeps its own artifacts.

Two worktrees keep independent artifacts but share compiler results keyed by compiler binary, JSON input and arguments. A hit reuses output; a miss compiles and stores it. Unchanged coverage reuses compiled probes; a source edit triggers a full instrumented compile.

To check cache use, enable compiler-cache tracing and look for hit, miss, published or bypass events and their reasons:

RUST_LOG=foundry_compilers::compiler_cache=trace forgeds build

--force bypasses the shared cache. The cache directory can grow large; it can be symlinked to storage intended for disposable build output. Optional secondary storage through an already-running sccache 0.19.0 daemon is described in the compiler-cache documentation. It is separate from RUSTC_WRAPPER and is not required for local reuse.

Use Solar for development checks

My ds-solidity skill in dsstack pairs forgeds with Solar for compatible local and CI development builds and tests. Install Solar separately, honoring the project's pin, and resolve both tools from Cargo's bin directory. Run through the project's wrappers and preserve its Solidity and EVM settings.

Use Solar for instrumented coverage iteration where compatible. The shared compiler cache supports both solc and Solar, with keys that include the compiler executable. A cache hit skips compilation; tests and coverage analysis still run on an unchanged coverage rerun.

Keep the project's approved compiler for deployed bytecode, required coverage and release artifacts, and retain project-required coverage modes.

cargo install solar-compiler --locked
forgeds build --use solar
forgeds test --use solar --mt <test_name>
forgeds coverage --instrumented --use solar --report summary --report gaps

Measured behavior

The comparison uses Rip.xyz’s NFT marketplace and vault contracts, Ensemble’s tokenized strategy vaults, and Diesis’s chain system contracts and Solidity interfaces.

The contract sources were built with test and deployment-script entrypoints excluded. Each toolchain used the same checkout and project optimizer and viaIR settings, with Foundry set to four threads. Both started with empty artifact folders and project caches. The figures show one local build per case, including artifact generation.

For compilation, the results were Rip.xyz: 8.00 seconds with forge + solc and 0.15 seconds with forgeds + Solar; Ensemble: 51.51 seconds with forge + solc and 0.89 seconds with forgeds + Solar; Diesis: 37.76 seconds with forge + solc and 0.57 seconds with forgeds + Solar.

Contract build times, forge plus solc versus forgeds plus Solar: Rip.xyz NFT marketplace and vaults, 8.00 versus 0.15 seconds; Ensemble strategy vaults, 51.51 versus 0.89 seconds; Diesis system contracts, 37.76 versus 0.57 seconds. Empty project outputs and no shared-cache reuse for the compilation measurement.

On another build with fresh artifact folders and project caches, forgeds + Solar finished in 0.09 seconds for Rip.xyz, 0.89 seconds for Ensemble, 0.18 seconds for Diesis. Rip.xyz and Diesis reused shared compiler results; Ensemble repeated the compilation. Each repeat run produced the same Solar artifacts as its uncached build. The forge + solc baseline is the same build shown in the first chart.

Repeat builds into fresh project outputs: forge plus solc baseline versus forgeds plus Solar. Rip.xyz 8.00 versus 0.09 seconds; Ensemble 51.51 versus 0.89 seconds; Diesis 37.76 versus 0.18 seconds. Rip.xyz and Diesis reuse shared compiler results; Ensemble recompiles.

The comparison uses forge 1.8.6 with each project’s pinned solc: 0.8.37 for Rip.xyz, 0.8.35 for Ensemble and 0.8.38 for Diesis. The other toolchain is forgeds 4ca15fc with Solar 0.3.0. These are build timings; they exclude running tests.

Instrumented coverage can reuse the compiled build too. Tests and coverage analysis still run. Editing a source file triggers a full instrumented compile, so focused tests remain useful while making changes.

Documentation and development story

Read the feature guide for the supported flags and limitations, the release page for binaries, and the blog post for the coverage problem and worktree measurements that led to these modifications.