HarborHarbor
DocumentationGuidesPlugins
Get Started

Your first exec

Write multi-step TypeScript that calls real plugin tools.

hrbr exec runs TypeScript inside a Harbor Cloud isolate. Your workspace's plugin namespaces (linearMcp, githubMcp, …) and the orbit.* runtime are pre-bound as globals.

Prerequisite: at least one plugin in your workspace is ready. If not, see Install your first plugin.

One-liner

hrbr exec 'return await linearMcp.listIssues({ limit: 5 })'

That's the smallest exec. Returns the latest five Linear issues as TOON.

Multi-step from a file

For anything longer, write a .ts file and pipe it in:

triage.ts
const issues = await linearMcp.listIssues({
  filter: { state: { type: { eq: "started" } } },
  limit: 10,
});

const stale = issues.filter((i) => {
  const days = (Date.now() - new Date(i.updatedAt).getTime()) / 86_400_000;
  return days > 7;
});

return {
  total: issues.length,
  stale: stale.length,
  titles: stale.map((i) => i.title),
};
hrbr exec -f triage.ts

You just filtered + transformed Linear data with zero plumbing. Every plugin call became a span on the run's trace.

Using orbit.*

orbit.* is your workspace's runtime — storage, cache, db, ai, tools, socket. See Concepts → Orbit Runtime.

// Memoize an expensive search for 10 minutes
const matches = await orbit.cache.fetch(
  "recent-incidents",
  () => sentryMcp.listIssues({ since: "7d", status: "unresolved" }),
  { ttl: "10m" },
);

// Save a summary as a workspace artifact
await orbit.storage.put("incident-summary.md", `# Latest\n\n${matches.length} unresolved`);
return await orbit.storage.url("incident-summary.md", { expiresIn: "1d" });

When the agent uses exec

When you ask Claude / Cursor / Codex / Gemini something like

"Find Linear issues that mention payment failures and tag them."

…the agent calls Harbor's inspect tool to find linear-mcp.search and linear-mcp.add_label, then calls exec with the TypeScript that wires them together. You don't need to teach the agent the plugin SDK — the meta skill harbor-exec already does.

The 30-second cap

Synchronous exec runs are capped at 30 s. Anything longer auto-routes to the durable Workflows lane — see Multi-step with retries.

Where to go next