Skip to content
Foundry
Esc
↑↓navigate↵open⌘Jpreview
On this page

Using Marbles

Explore the capabilities you can combine in a local automation.

Once you have run one step, you can add capabilities independently. These examples introduce each one; Foundation explains how their definitions, instances, and contexts fit together.

Run once or keep running

Use marbles roll <name> for one result. Use marbles and press Enter to open the dashboard and start schedules and monitors. The dashboard also lets you launch work and answer questions. A schedule declared in a file needs a running Marbles process to execute.

For a local unattended loop, marbles run </dev/null starts immediately with plain output. It cannot answer questions. See CLI modes.

Launch work from an MCP client

The source-checkout MCP server lets an external agent discover your definitions and start work over STDIO. Use dispatch_workflow for a named workflow or step, or dispatch_agent for agent work. Both return a runId without waiting for completion.

Follow either run in one CLI call:

marbles watch <runId>

Keep the MCP server connected while work runs. The watcher replays output already produced, follows new output, and exits when the run finishes. CLI reference covers exit codes, state selection, and interruption.

Give work input

Install the schema library in your project:

bun add zod@4.4.3

Save this as .foundry/marbles/count.ts:

import { step } from "@foundry.sh/marbles";
import { z } from "zod";

step("count")
  .input(z.object({ extension: z.string() }))
  .do(async ({ input, workspaces }) => {
    const files = await workspaces.current.files();
    return {
      extension: input.extension,
      files: files.filter((file) => file.path.endsWith(input.extension)).length,
    };
  });

Run marbles roll count --input '{"extension":".ts"}'. The schema validates input and supplies its TypeScript type. Schemas exposing Standard JSON Schema also describe the dashboard’s input form; other schemas use a JSON field. Input and output.

Run commands

A step can be one command:

import { step } from "@foundry.sh/marbles";

step("test-project").exec("bun test");

Use this in a project with Bun tests. Run marbles roll test-project and inspect its exit code and output. A nonzero exit fails the step. Commands also work inside .do() through exec. Execution context.

Connect steps into workflows

A workflow connects steps through their inputs and results. Run dependent work in order and independent work in parallel. For example, collect test results and review findings before producing a report.

Composition builds a small working tree. Software Factory applies the same model to implementation, verification, and approval.

The Workflows runtime records results for both commands and agent work. Durability covers waiting, retries, and restarts.

Work with projects and sandboxes

workspaces.current reads your project. workspace({ path: "../other-project" }) declares another directory. Git worktree callbacks give a task its own checkout; commands and agent sessions opened inside inherit that location. These operations come from Workspaces.

sandbox(...) declares an isolated execution environment, which starts on use. Choose its mounts, network access, and resources explicitly. The sandbox runtime is optional. Workspaces and sandboxes. The Sandbox library supplies the underlying file, command, and container interfaces.

Add an agent and keep its conversation

With an installed, authenticated Claude Code or Codex CLI, save this as .foundry/marbles/explain.ts:

import { agent, step } from "@foundry.sh/marbles";

const guide = agent({ prompt: "Explain this project without editing files." });

step("explain").do(async ({ agents }) => {
  const session = await agents.session(guide);
  return (await session.generate("What are the main parts of this project?"))
    .text;
});

Run marbles roll explain. Use a session for multiple turns; keep its session.ref to continue it in a later run. Skills add reusable instructions and files. Agents and sessions.

Agents keeps the conversation; Models resolves the provider and model. Marbles gives their execution the owning step’s stream, cancellation, and retry policy.

For a ready-made starting point, marbles init developer creates a review module. init without a choice creates a project summary. These are optional starters; project setup lists them.

Ask a person and publish results

ask.approval(...) and ask.question(...) pause a step for a dashboard answer. report.result({ title, body }) posts a readable result to the Feed. report.artifact(definition, files, { body }) saves versioned files and posts the supplied body to the Feed with a reference to that version. Use artifact(...).write(...) for saved state that needs no Feed announcement.

Use the dashboard for work that asks questions. A one-shot roll or an unattended loop cancels at an ask. Contexts explains these operations; human approval puts them together.

Versioned outputs use Artifacts. Artifacts and results explains when to return a value, post a message, or save files for a later run.

Schedule work and react to changes

Save this complete module as .foundry/marbles/heartbeat.ts:

import { monitor, schedule, step } from "@foundry.sh/marbles";

const heartbeat = step("heartbeat").do(({ log }) => {
  log("Marbles is running");
  return { alive: true };
});
schedule(heartbeat).every("30s");

monitor("**/*.md")
  .every("30s")
  .do(({ files, log }) => log(files));

Open marbles, press Enter, and wait for a tick. The step logs every 30 seconds while the loop is active. The monitor reports existing Markdown files on its first poll, then changes on later polls. HTTP monitors use the same pattern for a URL. Schedules and monitors.

Choose a use case

Build Combine
Software Factory Issues, work logs, implementation, review, delivery, and on-call reports.
Evaluations Model comparisons, skill checks, and feedback from file changes.
Design Briefs, wireframes, design iterations, and token maintenance.

Continue with Foundation to understand the model behind these capabilities. See safety and limits when running agent work or unfamiliar modules.

Was this page helpful?