ferretd is the experimental long-running developer service for
Ferret. It is intended to coordinate
language tooling, workspaces, execution sessions, and debug sessions for CLI,
Lab, and editor integrations.
The repository contains a local gRPC daemon with process-local Ferret source workspaces and execution sessions, a supported Go client, an experimental language server, and a single-session Debug Adapter Protocol (DAP) server over stdio. The Ferret VM, compiler, runtime, debugger semantics, and language semantics remain owned by the main Ferret project.
Requires Go 1.26.1 or newer.
make buildThe binary is written to bin/ferretd. Release builds can override the default
development version:
make build VERSION=v0.1.0Create and push a SemVer release tag from a clean working tree:
make release v0.1.0The tag triggers the GoReleaser workflow, which builds the supported platform archives and creates a draft GitHub release. Review its artifacts and release notes before publishing it manually.
make test
make lint
make generate
make proto-lint./bin/ferretd --version
./bin/ferretd serve
./bin/ferretd serve --endpoint unix:///tmp/ferretd.sock
./bin/ferretd lsp
./bin/ferretd dapserve starts the local daemon and waits for an interrupt or a Shutdown RPC.
It uses $XDG_RUNTIME_DIR/ferret/ferretd.sock on macOS and Linux, falling back
to the user cache directory, and \\.\pipe\ferretd on Windows. Explicit local
endpoints use unix:///absolute/path or npipe:////./pipe/name; TCP is not
supported. Daemon logs go to stderr.
The supported Go client discovers the default endpoint, performs API compatibility negotiation, and exposes daemon, workspace, and execution operations:
c, err := client.Dial(ctx)
if err != nil {
return err
}
defer c.Close()
info, err := c.Info(ctx)
workspace, err := c.Workspaces().Open(ctx, projectRoot)
session, err := c.Executions().CreateSession(ctx, client.CreateSessionRequest{
WorkspaceID: workspace.ID,
RelativePath: "main.fql",
})
execution, err := c.Executions().CreateExecution(ctx, client.CreateExecutionRequest{
SessionID: session.ID,
Parameters: map[string]any{"url": "https://example.com"},
})
watcher, err := c.Executions().WatchExecution(ctx, execution.ID)
running, err := c.Executions().RunExecution(ctx, execution.ID)Opening a workspace recursively discovers lowercase .fql files, loads their
contents, and retains daemon-owned documents with Ferret syntax state and
diagnostics. No Ferret project manifest is required. The initial snapshot is
used for static file discovery. Creating a Session rereads its already-discovered
target from disk, retaining the revision when its saved contents are unchanged
and advancing the revision when its retained source changes. Files created,
deleted, or renamed after opening are not rediscovered; close and reopen the
workspace to update that file set.
Workspace state is in memory for the daemon process. Reopening the same cleaned
absolute root returns the same workspace ID, closing a client connection does
not close its workspaces, and Close is explicit and idempotent. The current
workspace RPC continues to expose identity and lifecycle operations rather than
documents or parser internals.
Each open workspace owns a Ferret engine with a read-write filesystem rooted at
the workspace directory. CreateSession refreshes and compiles the latest saved
contents of one already-discovered workspace-relative .fql document into an
immutable reusable plan. Existing Sessions keep their original source revision
and normal and lazy debug Plans. Each Execution owns isolated JSON-shaped
parameter bindings and a fresh, one-shot Ferret runtime session.
RunExecution returns the RUNNING snapshot immediately; execution then
continues independently of the triggering RPC context. Clients can observe the
latest lifecycle event and subsequent events with WatchExecution, cancel an
active execution, and retrieve terminal output or failure details until they
explicitly close the resource. Closing a workspace cascades through its Sessions
and Executions. DAP debug Sessions are independent retained children whose
lifetime is coordinated by the protocol-neutral debug manager.
lsp starts the experimental language server over stdin and stdout. It opens
the local roots supplied by LSP initialization, uses their static workspace
documents as a baseline, and gives versioned editor overlays precedence while
documents are open. Analysis snapshots are coalesced and cached per URI.
dap starts a protocol-pure, single-session debug adapter over stdin and
stdout. It launches one local .fql program, opens its workspace in-process,
and delegates breakpoints, stepping, frame inspection, variables, and
evaluation to Ferret through separate transport-neutral execution and debug
managers. It does not connect to ferretd serve or expose debugging through
gRPC. See
docs/dap.md for launch arguments and supported requests.
The daemon exposes API v1.1 DaemonService, WorkspaceService, and
ExecutionService contracts over a permission-restricted local transport, plus
the standard gRPC health service. The checked-in Go code under gen/ is
generated from proto/ with pinned Buf and protobuf tools. The debug protobuf
remains an ungenerated placeholder.
Daemon workspaces retain deterministically discovered source files, source
contents, Ferret parse trees, and syntax diagnostics. Session creation refreshes
an existing target from disk, but file discovery remains static. The language
server uses the shared workspace manager for static source baselines and supports
opening, changing, and closing .fql editor overlays with full-document
synchronization. Its navigation and references are document-local.
Debug protobuf generation, debug gRPC/client APIs, filesystem watching, create/delete/rename discovery, incremental synchronization, cross-file indexing, module resolution, workspace persistence, remote daemon operation, and LSP-over-gRPC are not implemented. DAP remains single-session stdio only. Execution sessions do not add queues, durable replay, persistence, background automatic recompilation, or REPL state.
See docs/architecture.md for the intended architecture and docs/lsp.md for experimental editor setup.