A collection of production-ready Effect utilities and integrations.
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,asOptionvariants 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
diffcommand for CI/CD - API wrapper generation - Generate typed CRUD operations with
--include-api
| 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/aiChat, generateText, etc.
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 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,useEffectOnMountfor 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
@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.
@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.
| Package | Description |
|---|---|
| @overeng/utils/node/playwright | Effect-native Playwright wrappers with OTEL integration |
- Service tags -
PwPage,PwBrowserContextfor dependency injection - Structured errors - All operations wrapped with
PwOpErrorfor consistent error handling - OTEL spans - Automatic tracing with cross-process trace propagation
- Test helpers -
withTestCtxfor automatic layer provision in Playwright tests
| 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
| 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 -
--checkmode verifies files are up to date
This repo uses devenv to provide a consistent toolchain. Run commands inside the shell:
devenv shelldevenv tasks run buck2:editor:publishdevenv tasks run buck2:quickPublish Buck-produced declarations to package dist directories when source-side
tools or editors need them:
devenv tasks run buck2:typescript:materialize-dist# All tests
devenv tasks run test:run
# Single package (e.g., utils, genie)
devenv tasks run test:utils
devenv tasks run test:genie
# 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:watchThe aggregate starts test:buck2:unit after genie:check, independently of
editor dependency publication. It first prebuilds every declared Vitest collection
product from buck2-test-authority.json, then executes the 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 bounded selection's exact inventory, source-task ownership and baseline counts.
Prebuilding changes scheduling only: missing or malformed products, coverage drift,
failed bounded execution and missing source evidence still fail the aggregate.
Buck is the only repository-wide TypeScript check authority:
devenv tasks run buck2:quickThe 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:checkmkConsumerBuckRoot 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.
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.
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:targetShell 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.
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.
The entrypoint reads the tracked private archive origin from
archive_origin.trusted_url_prefix and archive_origin.trusted_tier, including
roots generated by mkConsumerBuckRoot. 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 without archive-origin metadata use the same 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 and
the archive origin concurrently 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; an unavailable archive origin selects the registry while retaining a
reachable REAPI session. Writers still fail closed on REAPI outages. Outage
overrides are invocation-local and do not change tracked configuration.
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.
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:checkCLI 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# Check formatting + lint
devenv tasks run lint:check
# Auto-fix formatting + lint issues
devenv tasks run lint:fixEach package follows modern ESM conventions:
- Source files in
src/(TypeScript with.tsextension) - Entry point at
src/mod.ts - Compiled output in
dist/(gitignored) - Development exports point to source files
- Published exports point to compiled JavaScript
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.