Skip to content

About

A collection of production-ready Effect utilities and integrations.

Topics

Resources

Stars

86 stars

Watchers

0 watching

Forks

Latest commit

 

History

2,430 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@overeng Effect Utils

A collection of production-ready Effect utilities and integrations.

Namespace scheduling

Namespace priorities express queue order across the shared projects. Lower numbers start first; any explicit priority precedes an unspecified priority.

Priority Work
1 effect-utils delivery
2 Smalltalk, PTY and tooling delivery
3 LiveStore delivery
4 effect-utils background
5 Smalltalk and tooling background
6 LiveStore background

Delivery includes required-check prerequisites, main verification, releases and actual deployments. Background includes optional benchmarks, advisory reports and maintenance. A scheduled verification is still delivery. Priorities do not reserve capacity or preempt running jobs; there is no new concurrency cap.

For effect-utils, required product checks, cache contract proofs, live integrations, compiled-product publication and required Storybook play tests use 1 on both platforms. Optional Storybook previews, cold-bootstrap/GC proofs, Devenv performance, Nix closure measurements, source-shape measurements on main, measurement reports, pipeline traces, alignment notices and review-request notifications use 4. The required PR source-shape check retains delivery priority. Shapes, caches, access controls, required checks and workflow frequency are independent of these labels.

Standalone Nix-staged JavaScript and TypeScript

devenv tasks run lint:check:standalone-staging (included in PR lint:check) checks nix/standalone-staging.json. Each standalone source must import only Node builtins (with or without the node: prefix), including re-exports, dynamic imports and require. Whole-declaration import type / export type edges are erased and ignored. Inline-only import { type X } still resolves its module under Node's type stripping, so it is checked as a runtime edge (even though Bun elides it). This matches the repository's verbatimModuleSyntax policy and the isolated Node proof. Non-literal runtime dependencies are rejected. An explicitly rewritten edge may name another isolation-checked source; the pnpm source-input stager uses this for its store-path rewrite of sync-resolver.ts. Import-form fixtures run both runtimes explicitly (NODE_BIN / BUN_BIN, or node / bun on the task PATH), independently of the test runner's host runtime.

Each source is also imported by Node 24 from a fresh directory with no node_modules, stripping TS types and applying only the declared store-path rewrite. CLI entries must reach their exact declared argument-validation error; other initialization errors fail. The native hook receives an explicit fixture entrypoint for its resolver registration. The inventory's extensions map is the single extension authority shared by the Nix scanner and isolation checks. A true value permits isolated Node imports; false keeps JSX/TSX visible to the scanner but rejects standalone entries with an explicit unsupported-extension diagnostic instead of silently skipping them.

The completeness check scans every position in tracked and untracked, non-ignored *.nix files for JS/TS filename references, including comments, strings, interpolation, shell code, globs and output names. It does not parse staging constructs. Every file containing such a reference must have a nixFiles entry: stages: true requires at least one isolation-checked source; otherwise noStandaloneStaging requires a one-line reason (workspace execution, deliberate closure, fixture, build rules, or non-source names). Each listed source must still appear as a path/reference fragment in its declared Nix file. Stale source and file classifications fail.

This part-1 gate is deliberately file-level: a new staging inside an already classified file, including a noStandaloneStaging file, is not detected. Extensions assembled by computation, such as "x." + "ts", also evade the token scan. The consumer lane in #1994 part 2 is the backstop and gates published; this part-1 inventory guard does not replace that consumer proof.

Packages

GitHub Actions retained artifacts

@overeng/gh-ci-utils provides read-only artifact inspection through the same configured GitHub authentication as its CI commands:

gh-ci-utils artifacts list 123 --repo example-org/example-repo --page 1
gh-ci-utils artifacts members 123 --repo example-org/example-repo --artifact 456
gh-ci-utils artifacts read 123 --repo example-org/example-repo --artifact 456 --member cost.json
gh-ci-utils artifacts read 123 --repo example-org/example-repo --artifact 456 --member log.txt --offset 1048576 --length 65536
gh-ci-utils artifacts read 123 --repo example-org/example-repo --artifact 456 --member log.txt --tail-bytes 65536

Output is terminal-safe JSON with explicit repository, run, and artifact provenance. The members response includes totalCount, equal to members.length (including directory entries). Artifact names never imply a job association. Expired artifacts, missing artifacts or members, and run mismatches fail explicitly. Member reads select one exact portable relative path; there is no automatic extraction or binary/raw output.

Reads without window flags return the complete member with the existing output shape. For larger text members, --length M selects the first M bytes; --offset N --length M selects a byte range, and --tail-bytes M selects the last M bytes. Offset requires length; tail is mutually exclusive with either offset or length. Values must be nonnegative safe integers, and length/tail must be at most 262144 bytes (256 KiB). Invalid selections fail with ArtifactError reason invalid-selection before download.

Windows count UTF-8 bytes, not characters or lines. Start edges advance past partial codepoints and end edges retreat to complete codepoints; no replacement characters are introduced. Offsets beyond EOF clamp to EOF. Zero-byte windows are valid; an empty window inside a codepoint reports the next codepoint boundary as its offset. Windowed content adds window: { offset, length, totalBytes } describing the actual aligned bytes returned, while decompressedBytes remains the entire member size. The whole selected member is still streamed and checked for CRC integrity, valid UTF-8 and binary content, including bytes outside the window. Corruption fails with unsafe-archive; binary or malformed UTF-8 content fails with binary-content.

Hard limits are 100 artifacts per page (pages 1–1000), 1 MiB metadata responses, 32 MiB compressed downloads, 1024 ZIP entries, 1024-byte member paths, 8 MiB decompressed per member, and 256 KiB selected text/escaped JSON output including its envelope and final newline. Limits apply to actual streamed bytes as well as advertised sizes. Windowing does not increase any limit or skip full-member validation. The entire escaped JSON document must still fit: even a valid 256 KiB window can fail with limit-exceeded because of metadata or JSON/terminal escaping; request a smaller window instead. Oversized output fails instead of silently truncating. Only unencrypted stored/DEFLATE members without ZIP64 member fields are supported. Bounded ZIP64 directory records are supported by the maintained parser; directory/member counts, offsets and sizes are independently bounded. Unsafe/duplicate paths, symlinks, special files, inconsistent headers, and corrupt selected-member contents are rejected. Metadata enumeration does not decompress members. Signed storage redirects are allowlisted and receive no GitHub authorization header.

Notion Integration

Full-featured Effect-native Notion API client with type-safe schema generation.

Effect-native HTTP client for the Notion API with typed queries

  • Schema-aware queries - Pass Effect schemas to get fully typed results with automatic decoding
  • Markdown conversion - Convert pages/blocks to Markdown with customizable transformers
  • Streaming API - Auto-pagination via Effect Streams for all list operations

Comprehensive Effect schemas for all Notion API types

  • Complete coverage - Schemas for all 27 block types and 21+ property types
  • Property transforms - asString, asNumber, asOption variants for ergonomic access
  • Write support - Dedicated write schemas for creating/updating pages

CLI tool to generate type-safe schemas from your Notion databases

  • Schema generation - Generate typed schemas from live Notion databases
  • Drift detection - Track schema changes with diff command for CI/CD
  • API wrapper generation - Generate typed CRUD operations with --include-api

AI Integration

Package Description
@overeng/effect-ai-claude-cli Claude CLI provider for Effect AI

Use your Claude Code subscription instead of paying for API calls. Implements Effect AI's LanguageModel interface by delegating to the claude CLI.

  • Subscription-based - Use your existing Claude Code subscription (much cheaper than API)
  • No API keys - CLI handles authentication via your subscription
  • Full LanguageModel support - Works with @effect/ai Chat, generateText, etc.

Schema Forms

Headless form library for Effect Schemas with accessible React Aria implementation.

Package Description
@overeng/effect-schema-form Headless form component with schema introspection
@overeng/effect-schema-form-aria Styled React Aria components with Tailwind CSS (Storybook)
  • Schema introspection - Automatically generate form fields from Effect Schema structure
  • Headless architecture - Bring your own components or use pre-built React Aria implementation
  • Tagged struct support - Automatic handling of discriminated unions with labeled groups
  • Flexible rendering - Provider pattern, render props, or hooks API for full control
  • Accessible by default - React Aria Components with WCAG compliance

React Integration

React hooks and utilities for building Effect-powered applications.

Package Description
@overeng/effect-react React integration for Effect runtime with hooks and context providers
@overeng/react-inspector DevTools-style inspectors with Effect Schema support (Storybook)
  • EffectProvider - Initialize Effect runtime from a Layer and provide to React tree
  • Hooks API - useEffectRunner, useEffectCallback, useEffectOnMount for running effects in components
  • Automatic error handling - Built-in error boundaries with custom error components
  • DevTools inspectors - Browser-style object/table inspectors with Effect Schema awareness
  • Type-safe runtime access - Direct access to Effect runtime for advanced use cases

Document Outlines

@overeng/outline provides theme-free outline models and accessible React Aria navigation. Import @overeng/outline/model for DOM-independent hierarchy normalization, active-section selection, and fixed-pitch preview geometry.

Callers own stable section IDs, ordered measurements, the reading edge, and scrolling. An OutlineScrollAdapter connects those measurements to getActiveSection; useOutlineRail owns hover, focus retention, the keyboard opener, and Escape focus return. Render OutlineLink with a navigation callback or native section hrefs. Pass the active ID from actual scroll position, not the last click. The package supplies no theme, document discovery, domain extraction, or virtualization.

Run devenv tasks run test:outline for the focused behavioral suite. Its scoped buck2:editor:publish:test:outline prerequisite publishes the package's Buck-owned dependency view plus the root and OpenTelemetry bootstrap views, without materializing unrelated package views.

Browser Telemetry

@overeng/otel-browser provides scoped Effect tracing and OTLP/HTTP traces and metrics for browser applications. Compose BrowserTelemetry.layer({ identity, environment: 'dev', endpoint: '/otlp' }) with BrowserPlatform.layerWindow, using a validated ServiceIdentity from @overeng/otel-contract. Set endpoint: undefined for the bounded, in-memory span ring without network export. The endpoint must be same-origin; the application server owns collector relay.

Optional Interactions.layer, LongFrames.layer, and WebVitals.layer record browser performance without coupling telemetry to a UI framework. Scoped listeners and observers are removed at shutdown. The transport uses beacon/keepalive on page hide and drops offline exports rather than retaining an unbounded queue. @overeng/otel-browser/vite supplies otlpDevProxy() for development and preview; it reads OTEL_EXPORTER_OTLP_ENDPOINT and strips application cookies before collector forwarding.

DOM-free W3C propagation lives in @overeng/otel-contract/Traceparent: decode/encode validate version-00 context, while headers, wsUrl, and withField carry the current span over HTTP, WebSocket upgrade URLs, and messages. Server consumers use fromUrl and fromField.

The public browser adapters and imperative telemetry methods use named arguments, for example telemetry.recordSpan({ name: 'browser.render', startMs: 10, endMs: 25 }) and Traceparent.wsUrl({ url: new URL('/stream', location.href) }). UI histograms are defined through schema-first OtelMetric contracts, preserving their exported metric identities and bucket policies.

Playwright Integration

Package Description
@overeng/utils/node/playwright Effect-native Playwright wrappers with OTEL integration
  • Service tags - PwPage, PwBrowserContext for dependency injection
  • Structured errors - All operations wrapped with PwOpError for consistent error handling
  • OTEL spans - Automatic tracing with cross-process trace propagation
  • Test helpers - withTestCtx for automatic layer provision in Playwright tests

Peer-to-peer QUIC

Effect 4 bindings for authenticated peer-to-peer QUIC and schema-framed messages in Node and Bun desktop/server applications. See the package README for usage and limitations.

Package Description
@overeng/effect-iroh Effect wrapper for the iroh binding

Utilities

Package Description
@overeng/utils Distributed locks, log bridging, and debug utilities

Key features:

  • SharedWorker→Tab log bridging via BroadcastChannel (@overeng/utils/browser)
  • Scope/finalizer debugging and active handles monitoring
  • File system-backed distributed locks with TTL expiration
  • Workspace-aware command helpers with optional logging/retention

Developer Tools

Package Description
@overeng/genie TypeScript-based config file generator
@overeng/oxc-config Shared oxlint and oxfmt configuration

Genie generates package.json, tsconfig.json, and GitHub workflow files from TypeScript sources (.genie.ts files). Features include:

  • Type-safe config - Define configs as TypeScript with full autocomplete
  • Consistent formatting - Auto-formats via oxfmt
  • Read-only protection - Generated files are read-only by default
  • CI integration - --check mode verifies files are up to date

The content-address Rust contract is compiled from its Effect schema with devenv tasks run content-address:contract:generate. This task bootstraps the generator's dependency view from the current standalone Buck sources before running packages/@overeng/content-address/src/generate-contract.ts; it does not require the contract to pass freshness first. genie:check (including the CI freshness lane) runs content-address:contract:check, which uses that same runtime and requires byte-identical regeneration of the committed contract and provenance. The check restores checkout read-only permissions without rewriting any bytes.

Quick Start

Enter the dev shell

This repo uses devenv to provide a consistent toolchain. Run commands inside the shell:

devenv shell

Publish Dependency Views

Source-side generator freshness (genie:check) needs the root dependency view: it directly runs buck2:editor:bootstrap for only . and packages/@overeng/otel-contract, never whole-workspace publication. The static generator closure checker remains self-contained. Shell entry, genie:run, and lint:fix do not publish dependency views; explicitly regenerate and publish source-generator dependencies with:

devenv tasks run buck2:editor:materialize

Publish only requested consumers (JSON package paths), or omit the environment variable to reconcile changes since origin/main. Automatic selection uses the pnpm lockfile importer graph, including transitive workspace-dependent consumers. Global dependency inputs or unproven ownership fail closed to the complete authority with a diagnostic.

EDITOR_VIEW_PACKAGES='["packages/@overeng/notion-core"]' devenv tasks run buck2:editor:publish

The default never substitutes a whole-workspace publication for an empty change set. Every automated consumer selects its own scoped publisher. Aggregate source-test chains preserve each package's own publication prerequisite; their shared harness publisher covers only the selected generator/module-script views, not the union of source-test packages. The full operation is manual only and currently exceeds its 300-second deadline; verification optimization is tracked in #1915:

devenv tasks run buck2:editor:publish:all

Each authority/bootstrap/publication invocation has a 300-second total deadline (plus a 5-second forced-kill grace), including Buck builds, filesystem work and lock waits. A separate supervisor owns the publication session and always escalates to a group-wide kill after the grace, even if the authority already exited. Fingerprint admission closes on termination. Expiry prints a deadline diagnostic and fails nonzero; partial publication is never reported as success. This bounds shared-lane occupancy well below the 53-minute TT-148 incident. Both view preparations and fingerprint subprocesses are limited to four workers, matching the native host-wide walk cap. Only immutable Nix-store inputs are memoized, keyed by the tool and complete fingerprint arguments; mutable Buck outputs are always re-proven. Phase diagnostics are written as work advances, with phase spans on completion, failure, and SIGTERM.

Maintain Buck Outputs and Idle Daemons

devenv tasks run buck2:maintain
# Preview the same repository policy and inspect its complete receipt:
mr store buck-maintain --config ./buck-maintain.json --dry-run --json

buck-maintain.json contains neutral defaults for the current checkout: a soft 2 GiB output budget, 24-hour recent-output retention, and a 30-minute idle-daemon policy. Maintenance uses native Buck clean/kill commands only; the budget is not a hard disk limit. It does not configure daemon_idle_timeout_s. By default only the current ST_AGENT owner is eligible, unowned worktrees are excluded, and no seat or explicit owner configuration means report-only. Active commands (including LSP) and live Buck clients prevent maintenance. The legacy scripts/buck2-daemon-reaper.ts entrypoint delegates to the same runtime; the independent reaper policy and its old flags are removed. Use --config to configure policy and --dry-run to preview it. See the command reference for ownership, blackout windows, native cleanup, and the remaining client-arrival race between final activity recheck and kill.

Check All TypeScript Projects

devenv tasks run buck2:quick

Publish Buck-produced declarations to package dist directories when source-side tools or editors need them:

devenv tasks run buck2:typescript:materialize-dist

Run Tests

# All tests
devenv tasks run test:run

# Single package (e.g., utils, genie)
devenv tasks run test:utils
devenv tasks run test:genie

# Rust interop generator integration tests (Bun)
devenv tasks run buck2:rust:generators:test

# Integration tests (requires NOTION_API_TOKEN for Notion packages)
NOTION_API_TOKEN=secret_xxx devenv tasks run test:integration

# Watch mode
devenv tasks run test:watch

The aggregate starts test:buck2:unit after genie:check, independently of editor dependency publication. It first prebuilds the selected Vitest collection products from buck2-test-authority.json, then executes the selected bounded lanes in the existing single Buck test invocation. The prebuild performs no source tests and does not cache source reports or coverage verdicts.

After the source suites and bounded verdicts finish, test:run still invokes the baseline-collection gate. That gate resolves the identical collection targets with the same local-only host-platform Buck build, so current inputs are checked even when the products are warm. It then validates the complete filesystem census, each selected bounded lane's exact inventory, source-task ownership and baseline counts. Missing or malformed products, coverage drift, failed bounded execution and missing selected source evidence still fail the aggregate.

genie/ci-workflow/test-platforms.json classifies aggregate source tasks, individual bounded Buck lanes, and every shared module shell script as Darwin-sensitive or platform-neutral, with a rationale for each. The required macOS lane sets EFFECT_UTILS_TEST_PLATFORM=darwin and runs only the Darwin subsets; Linux and an unset platform run both subsets. Disjointness and completeness are enforced against the generated Buck authority and discovered module scripts. The complete ownership authority is retained even when collection products and baseline evidence are scoped. Editor publication follows the selected source suites and module fixtures rather than publishing neutral-only package views. macOS still builds and smokes the native and compiled products to cover Darwin artifacts.

Infrastructure Bun suites outside package source roots run through source tasks rather than buck2-test-authority.json: genie:buck2:test covers the Buck projection suite, and buck2:rust:generators:test covers every test under buck2/rust/, including the interop service and wasm guest packager integration tests. Both tasks participate in test:run; the platform-neutral Rust generator suite runs in the Linux CI partition, while the Darwin partition retains only host-sensitive suites.

Type Checking

Buck is the only repository-wide TypeScript check authority:

devenv tasks run buck2:quick

The shared compiler options require erasableSyntaxOnly, so package and fixture typechecks reject TypeScript constructs requiring runtime transformation, such as parameter properties, enums, and runtime namespaces, before merge-group consumer tests. Source exports can therefore use Node's strip-only mode without TypeScript lowering; unrelated runtime requirements and JSX transforms still apply.

Audit cross-cell Buck provider identity separately:

devenv tasks run buck2:providers:check

Generated TypeScript package and root aggregate BUCK files record their projection source, generator, schema version, semantic fingerprint, and regeneration command. They deliberately do not enumerate the workspace-wide generator inputs: unrelated package additions must not rewrite package-local headers. Follow the projection source and its imports for the authoring provenance; the package projection reads the owning repository's Genie registry to resolve workspace dependencies and nested package exclusions. The fingerprint hashes the canonical projection data, not an enumerated list of filenames or the bytes of every source file. Freshness is enforced independently by devenv tasks run genie:check, which loads the generators and compares their complete formatted output with the committed files (packages/@overeng/genie/src/core/generation.ts). The warm genie:run task fingerprint separately covers generator sources, configured extra input globs, generated bytes, and CLI identity in nix/devenv-modules/tasks/shared/genie.nix; it does not parse these comments. Buck action/cache identity continues to come from declared target inputs, dependencies, and toolchain capabilities; no rule interprets the header as a dependency manifest or cache key. Rules that explicitly stage a BUCK file still hash its complete bytes.

Consumer Buck Roots

Consumers needing an always-eligible product manifest should pin ref published, not ref main; see the consumer pin contract.

mkConsumerBuckRoot accepts the named watcherPolicy argument. Its default, "mutable-checkout", emits file_watcher = watchman and retains fail-closed Watchman admission for interactive source edits. Roots copied into immutable Nix builds or filtered, immutable source checks must instead pass:

watcherPolicy = "immutable-input";

This emits file_watcher = fs_hash_crawler: declared inputs do not change during the build, so no Watchman executable or service is required. The from-source builder uses the same policy mapping. Unknown policies fail Nix evaluation with a message listing both allowed values; raw watcher-provider strings are not accepted.

The packaged Prelude explicitly clears RUSTC_WRAPPER and RUSTC_WORKSPACE_WRAPPER in Reindeer build-script action environments, matching the Rust toolchain and first-party launcher rules. A local Buck daemon started inside a Cargo development shell must not introduce ambient sccache selection. Compiler selection and cache identity remain owned by the declared Buck tools; inherited sccache settings cannot activate a wrapper when these selectors are empty.

First-party and Reindeer build-script launchers also declare PATH from the immutable Bash and coreutils capabilities. Bundled Prelude shims invoke Bash through /usr/bin/env and use dirname/realpath; they must not depend on the environment of whichever task first started the Buck daemon (aggregate tasks intentionally expose only Watchman on their own PATH).

TypeScript package projections retain census destinations below nested Buck packages, but resolve each input through its nearest owning BUCK (or BUCK.genie.ts during generation). For example, src/main.ts below parent/src/BUCK is staged from //parent/src:main.ts; only locally owned sources are exported by the parent. Each nested package must publish the explicit inputs the parent consumes with export_materialization_inputs, including test modules, snapshots and fixture data. Its target names escape $ as __dollar__, while staged destinations stay unchanged. This file-level contract preserves source-granular dependencies instead of introducing a second, nested-tree materialization interface. Project and runner configuration remain package-root files; declared projectInputs may reference nested files.

Consumer dependency generators declare the cell that exports patches from each nested checkout instead of loading that checkout's standalone BUCK files:

renderPnpmPackageTargets({
  metadata,
  sidecar,
  patchSourceCells: { 'repos/effect-utils': 'rules' },
})

The buck2-rules package exports the shared pnpm patch registry in its rules cell. Unmapped patch paths retain same-cell labels; mappings match complete path components, and the most specific checkout root wins.

Frozen source dependencies use an exact workspace-path-to-target mapping rather than resolving a label beneath an ignored runtime directory:

makePnpmStoreProjection({
  metadata,
  sidecar,
  workspaceTreeTargets: {
    '.devenv/pnpm-source-inputs/current/repos/sdk/client': 'pnpm_sources//:sdk_client_package_tree',
  },
})

The consumer owns that declared package tree and its cell. It must expose the frozen package bytes named by the lockfile, not a mutable checkout with the same path suffix. A source cell rooted at .devenv/pnpm-source-inputs can keep its generated BUCK outside the immutable current generation and assemble sources with empty_package_view (or package_view for packages with dependencies). The consumer's Nix source closure must supply the same cell, package bytes, and target declarations. The root continues to ignore .devenv wholesale. Unmapped workspace packages retain their conventional same-cell :package_tree labels; mapped labels participate in the projection fingerprint.

Workspace link: dependencies resolve relative to their importer, or relative to the lockfile root when pnpm emits them inside a package snapshot. Both forms reference the same workspace importer and package tree. Links must remain inside the repository; snapshot links must resolve to a known lockfile importer. Directory snapshots without their own importer view get a normalized store entry backed by their declared source tree. Their snapshot dependencies, including workspace links, remain explicit Buck edges rather than being lost behind a source-tree reference. Directory snapshots with an importer reuse its workspace tree and dependency view.

Dependency-view availability is derived from the complete required resolver context, not just a package's own platform fields. Required native dependencies retain their edges on supported machine platforms; their owners and importer views have no javascript_portable configuration. Generation still succeeds, but selecting an unsupported configuration fails analysis before execution. Optional native packages retain platform filtering. The normalized store schema is effect-utils/buck2-pnpm-store/v2; importer platforms lists supported configurations and variants covers only that set.

Put the effect-utils flake's pinned packages.<system>.buck2 on PATH (or use its bin/buck2 as BUCK2_BIN). Direct commands, agents and devenv tasks then share the same cache posture preflight; no separate task or probe command is required:

buck2 build //your/package:target

Shell activation and Buck task preparation publish the realized Nix capabilities into a stable real .buck2/capabilities cell. Publication is process-locked, installs immutable generation metadata first, and atomically replaces the watched defs.bzl last. Ordinary capability changes reach already-running daemons without a restart. The one-time cell-root symlink migration uses atomic exchange, then explicitly runs buck2 kill for this worktree's registered isolation directories: the symlink-to-directory transition changes native watch topology and requires a fresh daemon. The publisher logs each stop; a persistent migration marker makes a failed or interrupted stop retryable. Preparation diagnostics go to stderr, preserving command stdout when callers capture Buck output paths. The daemon regression starts and shuts down its own private Watchman service, using a fixture-only global config that permits nice 19; it does not depend on a host service on Linux or macOS.

The publisher fixture retains assertion failures before cleanup under ${XDG_STATE_HOME:-$HOME/.local/state}/buck2-cache-reports/capability-publisher/ and prints the private evidence directory. Each capture keeps at most five snapshots: the new capture and the four newest prior evidence directories. It contains the failed generation observation, copied generation metadata and publisher JSONs, shell job IDs/PIDs/states without command text, and native PID ancestry without command arguments or environment. CAPABILITY_TEST_EVIDENCE_DIR overrides the destination for focused proofs. Copies are best-effort observations while writers may still run, not an atomic snapshot or a Nix closure archive; collection errors are recorded explicitly.

Retained generations have indirect Nix GC roots under .buck2/capability-roots. The publisher keeps the three most recently published generations only when Buck's state files show no live worktree daemon in any isolation directory. Live or uncertain daemon state retains all generations; the next daemon-free publication restores the bound. This protects even idle daemons with cached old generation references. See the capability publication contract.

Tracked [buck2] file_watcher = watchman also opts into watcher admission, even without remote-cache configuration. The packaged entrypoint admits the actual Watchman service and canonical watched root with watchman --no-local watch-project <root> before native daemon startup. An attempt has a 2500 ms deadline and one retry for a timeout only. Successful root admission is cached for at most five seconds, scoped to the root, .watchmanconfig, PATH, HOME and socket environment identity. Un-niced default-service queries allow Watchman to spawn on demand on Linux and Darwin, including job-local CI runners. Niced clients use --no-spawn: they may connect to an existing service, but never create a permanently niced shared daemon. Only a proven-missing default service (the silent no-spawn client plus an absent computed socket) or Watchman's own startup refusal is diagnosed as a priority problem: start the service un-niced with watchman get-sockname outside the gate or provision the host service, and never relax the shared startup priority limit. Other niced failures keep their genuine executable or service diagnosis; admission never falls back to notify. An explicit WATCHMAN_SOCK also uses --no-spawn on every platform: admission must reach that owned service, not create a replacement. Missing, unhealthy or incorrectly rooted Watchman fails with the probe command and remediation; it never selects notify as an outage fallback. For an ancestor-root mismatch, run watchman watch <root> and rerun the displayed probe. Enter devenv shell if Watchman is missing from PATH.

Explicit unmanaged local watcher choices take precedence and remove stale managed watcher settings without disturbing the independent cache overlay. In particular, immutable Nix source products select fs_hash_crawler: they have no interactive edit loop, and Watchman's state-directory initialization is not permitted in the Nix sandbox. Mutable worktrees retain Watchman to avoid hashing the source tree on each command. Watchman-configured worktrees automatically transition the selected daemon isolation after successful admission: a missing provider marker or a changed provider stops only that worktree's registered daemon with the native --isolation-dir <selected> kill command before startup. The per-root/isolation marker and crash-released lock live outside Buck's daemon directory in ~/.buck/file-watcher-admission-v1/; native startup cleans the daemon directory, not these markers. Matching markers prevent repeated stops, and other worktrees and isolations are never stopped. Failed stops prevent startup and do not record successful migration. Maintenance kill, status, and log commands bypass Watchman admission so diagnosis and shutdown remain available during an outage.

When GATE_SLOT_CLASS is set, the packaged wrapper owns gated admission and teardown for the selected project/isolation. On Linux it compares native buck2 status plus /proc/<buck2d pid>/cgroup with the caller's own cgroup. Ownership is the nearest gate-slot-*.scope ancestor of the unified cgroup path: parent, nested action and sibling cgroups inside that scope are reused. An idle foreign daemon is stopped before the client runs, so its replacement and local actions inherit the job's lane limits and accounting. A daemon with a valid unified path outside any gate scope is foreign to a known caller gate scope. Missing unified membership or an unknown caller scope instead retains the daemon with a warning, never guessing permission to migrate it. A foreign daemon with active clients is retained and reused with exactly one stderr accounting warning naming its foreign cgroup; moving or interrupting another build/editor client is unsafe. The selected isolation follows the pinned native CLI/environment default and plain @file/--flagfile expansion, including nested files relative to the invocation directory. Python/stdin argfiles, config-backed cell-path fallback and other unresolved forms fail closed: one warning and no lifecycle status or kill calls, rather than guessing the unrelated default v2 daemon. Only Buck arguments before the expanded -- separator determine lifecycle identity and help/version bypass; executable payload such as -- --help does not bypass cleanup. Native run also accepts separator-free trailing payload, which can contain isolation-looking options. Lifecycle resolution conservatively supports run TARGET [-- payload] with Buck options before run; other run forms retain daemons with the same fail-closed warning rather than guessing where Buck options end.

An outer shell installs EXIT/INT/TERM/HUP traps and waits for its native client. At exit it invokes native buck2 kill only when a fresh status identifies the selected daemon and reports zero active commands, even if this invocation started it. Busy status quietly retains the daemon; unavailable/malformed status warns and never authorizes a kill. Cleanup preserves ordinary numeric exits; after a wrapper INT/TERM/HUP it restores the default disposition and re-raises the signal, so parents observe signal termination rather than an explicit 128+N exit. kill, status, and log remain diagnostic/lifecycle commands and bypass both gated admission and teardown. Signals already ignored on entry to Bash remain ignored as POSIX requires; the wrapper does not override that inherited caller policy. An injected BASH_ENV that replaces Bash's kill builtin with an external command can instead make Bash translate its self-SIGINT into numeric exit 130 (128+N); the agent command guard is one such environment. Native signal tests use the packaged interpreter without BASH_ENV and assert default SIGINT disposition before delivery.

Outside gate-slot, native warm-daemon behavior and the admitted-argument fast path are unchanged. A nested wrapper inherits the outer wrapper's cleanup ownership rather than stopping the daemon beneath its caller. No daemon memory cap or separate daemon unit is installed. At the pinned Buck2 revision, resource control places actions in a daemon-owned reusable cgroup pool; the public client protocol has no per-command caller-cgroup destination. Moving the daemon alone therefore moves local build work out of gate-slot's limits, while a daemon-unit memory cap would cap compiler/test actions too.

Buck's kill RPC has no conditional-idle form. At both start (foreign idle daemon migration) and exit (idle teardown), a new client can arrive between the final empty-active-commands status read and buck2 kill, and be interrupted. Wrapper exit teardown and mr store buck-maintain can both observe the same idle daemon in that window and send duplicate native kill RPCs; native kill is not serialized between those independent owners. Either observer can also race a new client arriving after its last idle check. Maintenance invokes the native executable, so it does not recursively trigger wrapper teardown. An already observed active client is never deliberately killed. Reusing a foreign busy daemon leaves an explicitly logged accounting gap for that invocation, and retaining a busy daemon at exit may keep its original job scope alive. Independent idle-daemon maintenance remains the backstop for this conservative concurrent-client case.

The existing explicit local [buck2] file_watcher = notify choice is retained for deliberate non-agent use, but is unsafe for agent builds: completed source writes can race notify's unsynchronized callback buffer and produce stale copied inputs. Agent workflows require a healthy, correctly rooted Watchman service instead. No new notify opt-in environment variable is introduced. Watchman output exclusions are defined by .watchmanconfig; Buck's separate [project] ignore settings alone do not prune notify's initial registrations.

RE client settings belong in .buckconfig, not invocation overrides. Pinned Buck ignores [buck2_re_client] values supplied by --config or --config-file. The entrypoint applies writer credentials/endpoints to the managed .buckconfig.local block before daemon startup. After changing client endpoints or credentials, stop the existing daemon with buck2 kill in the same project and isolation directory; changing config does not rebuild an existing RE client.

The checkout and mkConsumerBuckRoot set buck2_re_client.max_total_batch_size = 3145728 (3 MiB of blob payload). Pinned Buck2 counts payload bytes, not protobuf framing or per-blob digests, when batching uploads. The lower threshold leaves transport headroom under bazel-remote's 4 MiB gRPC receive limit; larger individual blobs use ByteStream with the same bounded chunk size. A server capability value of max_batch_total_size_bytes = 0 does not remove its gRPC message limit.

Standalone pnpm archives use native Buck download_file actions with the canonical registry URL, reviewed SHA-256 and byte size. Buck verifies bytes and defers materialization; warm archives need no transfer, while explicit fresh roots still download registry bytes. Downloads do not read the RE CAS. The private CAS and verified seeder remain optional infrastructure; there is no runtime archive-origin selection or automatic fallback. A future mirror or CAS read path needs a separate decision. Nix's per-digest fixed-output archives and copy-and-verify projection are unchanged.

Public read-only jobs set BUCK2_PUBLIC_CACHE_READ_ONLY=1; protected public publishers provide BUCK2_CACHE_WRITE_BASIC_AUTH. A private host resolves its own BUCK2_PRIVATE_CACHE_WRITE_AUTH=username:password credential and declares BUCK2_PRIVATE_CACHE_ADDRESS=grpc://<private-host>:<port>. The pinned entrypoint converts raw host credentials into BUCK2_PRIVATE_CACHE_WRITE_BASIC_AUTH; credentials never enter config files. Do not use a publisher credential as a host credential.

Configured REAPI roots use endpoint admission; an omitted remote_cache_enabled follows the execution policy's enabled default.

BUCK2_NO_REMOTE_CACHE=1 disables reads and uploads, and public read-only posture wins over either writer credential. The entrypoint probes REAPI capabilities with a 900 ms deadline, caches endpoint outcomes for five seconds in the user's cache directory, and emits a warning on every fail-open invocation. An unavailable read-only REAPI endpoint selects local execution. Writers still fail closed on REAPI outages. Outage overrides are invocation-local and do not change tracked configuration. Archive availability does not participate in REAPI admission.

Identical healthy read-only invocations reuse a shell fast path within the remaining probe lifetime, avoiding JavaScript startup in warm loops. Its cache key includes config contents, command arguments, working directory and exported environment; writers, config includes and external mode files bypass it.

The probe is an admission snapshot: an endpoint that disappears after a successful probe (including during its five-second cache lifetime) can still fail inside native Buck. Native Buck has no configurable RE connection retry limit or startup local-fallback switch at this pinned revision.

Only audited rules requesting the cache_hermetic execution constraint may reuse/upload; the default platform denies both even when root policy allows writes. The complete lane inventory and current sandbox limits are in the execution spec. Do not put credentials in tracked configuration.

Nix Artifact Import Checks

Validate the generic and JavaScript Buck product import boundaries without realizing repository products:

devenv tasks run nix:buck2-artifact-import:check
devenv tasks run nix:javascript-product-import:check

CLI packaging uses Buck products and the validated Nix import boundary described in workspace tools. Live pnpm workspaces share install policy and source-input algebra; Buck products use immutable dependency archives.

Fixed-source Nix products use NIX_BUILD_CORES for Buck execution (build -j), Tokio workers (build --config build.num_tokio_workers), and daemon blocking threads (BUCK2_MAX_BLOCKING_THREADS). An unset or zero Nix budget becomes one, not the host CPU count. Configuration overrides follow the build subcommand; only the isolation-directory flag is global.

Local builtins.getFlake calls use git+file:// references so Nix copies only Git-tracked sources, not ignored build outputs or development state. The shared test runner sets NIX_FLAKE_REF to that same Git reference. devenv tasks run lint:check:getflake checks this contract with negative fixtures; it also runs through nix:check:quick and check:quick. For a standalone check without shell evaluation, run node --test scripts/lint-getflake.unit.test.mjs and node scripts/lint-getflake.mjs.

check:all also evaluates every flake output for the host system without building anything:

devenv tasks run nix:flake:eval

Linting

# Check formatting + lint
devenv tasks run lint:check

# Auto-fix formatting + lint issues
devenv tasks run lint:fix

Package Structure

Each package follows modern ESM conventions:

  • Source files in src/ (TypeScript with .ts extension)
  • Entry point at src/mod.ts
  • Compiled output in dist/ (gitignored)
  • Development exports point to source files
  • Published exports point to compiled JavaScript

Contributing

This monorepo uses:

  • bun workspaces for package management
  • TypeScript project references for incremental builds
  • oxlint + oxfmt for linting and formatting
  • Vitest for testing
  • Effect for core functionality

See individual package READMEs for package-specific documentation.

About

A collection of production-ready Effect utilities and integrations.

Topics

Resources

Stars

86 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages