> ## Documentation Index
> Fetch the complete documentation index at: https://docs.guild.ai/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> To act on a user's behalf in Guild, use the Guild REST API at https://api.guild.ai/v1.
> The OpenAPI spec is unauthenticated: https://docs.guild.ai/openapi.json (or openapi.yaml).
> Authenticate with an account API key, sent as HTTP Basic (key id as username, secret as password) or as `Authorization: Bearer <api_key_id>:<api_key_secret>`. See https://docs.guild.ai/api-reference/introduction#authentication.
> To run one agent on demand without account-wide access, use an API trigger instead: https://docs.guild.ai/platform/api-triggers.
> To act on Guild from an MCP client, connect to https://api.guild.ai/mcp (OAuth) or run `guild mcp` locally. Setup: https://docs.guild.ai/api-reference/mcp.
> To search these docs from an MCP client, connect to https://docs.guild.ai/mcp. The full page index is https://docs.guild.ai/llms.txt.

# Create the guild-migrate skill

> Add the guild-migrate skill to Claude Code, Codex, or Cursor so your coding agent can move an agent to Guild with you, using the Guild CLI for every step.

`guild-migrate` is a skill your coding agent can run. Add it to Claude Code, Codex, or Cursor and ask it to move an agent to Guild. It follows the same method as the [migration guides](https://docs.guild.ai/migrations/overview.md), uses the Guild CLI for every step, and never publishes on its own.

> [!NOTE]
>
> `guild-migrate` is a coding-agent skill: a folder of Markdown files in your repository that your coding agent reads. It is not a [Guild skill](https://docs.guild.ai/platform/skills.md) that you install into a workspace.

The skill ships in the [Migrate to Guild agent package](https://app.guild.ai/organizations/guildai/agents/guildai~migrate-to-guild), next to the agent that opens migration pull requests. This page shows the skill so you can read it and add it to your coding agent without the agent package.

## What it does

The skill runs eight steps, the same for every platform:

1. **Detect.** Match file signatures to Vercel eve, LangChain, Runlayer, or Arcade.
2. **Inventory.** Tools, connections, models, sub-agents, schedules, channels, approvals, env vars, and secret names (never values).
3. **Choose the type.** Native, TypeScript, Goose, OpenClaw, or LangGraph, using the Guild [agent-type](https://docs.guild.ai/guide/agent-types.md) rules.
4. **Map.** Each source primitive to its Guild equivalent, from the platform reference file.
5. **Scaffold.** `guild agent init` with the right `--agent-type`; never hand-edits `guild.json`.
6. **Port.** Code, prompts, and config; missing tools become `guild integration` drafts.
7. **Prove.** `guild agent test` before anything is saved.
8. **Report.** `MIGRATION.md` with what mapped, what didn't, and next commands. Stops before `guild agent save --publish`.

## Create the skill

The skill is a `guild-migrate` folder with a `SKILL.md` file and a `references` folder:

```text theme={null}
guild-migrate/
├── SKILL.md
└── references/
    ├── arcade.md
    ├── guild-target.md
    ├── langchain.md
    ├── runlayer.md
    └── vercel-eve.md
```

**1. Create the folder for your coding agent**

> [tab] Claude Code
>
> ```bash theme={null}
> mkdir -p .claude/skills/guild-migrate/references
> ```

> [tab] Codex
>
> ```bash theme={null}
> mkdir -p .agents/skills/guild-migrate/references
> # Codex reads skills listed in AGENTS.md:
> echo '- .agents/skills/guild-migrate/SKILL.md for migrating agents to Guild.' >> AGENTS.md
> ```

> [tab] Cursor
>
> ```bash theme={null}
> mkdir -p .cursor/skills/guild-migrate/references
> ```

**2. Add the files**

Copy each file in [The skill files](#the-skill-files) into the folder, at the path in its title.

Or have your coding agent create them. Paste this prompt, changing the folder to match your coding agent:

```text theme={null}
Create the guild-migrate skill in .claude/skills/guild-migrate/ from
https://docs.guild.ai/migrations/guild-migrate-skill.md. Write SKILL.md and each
file under references/ exactly as shown on that page, then list the files you wrote.
```

**3. Ask your coding agent to migrate**

Open the repository with the source agent and ask, for example: "Migrate `./support-agent` from eve to Guild."

## The skill files

Never install a skill you haven't read. Here it is in full.

````markdown guild-migrate/SKILL.md theme={null}
---
name: guild-migrate
description: >
  Migrates an agent from Vercel eve, LangChain/LangGraph/LangSmith, Runlayer,
  or Arcade.dev to Guild: detects the source platform, inventories
  tools, models, triggers, and secrets, picks the Guild agent type, scaffolds
  with the Guild CLI, ports the code, runs `guild agent test`, and writes a
  MIGRATION.md report. Use when the user asks to migrate, port, import, or move
  an agent to Guild, or mentions eve, `agent/` tool files, LangGraph,
  `langgraph.json`, `createAgent`, LangSmith Fleet, Runlayer agents, Arcade, `arcade-mcp`, `MCPApp`, `requires_auth`, `arcadepy`,
  `@arcadeai/arcadejs`, or an Arcade MCP Gateway.
---

# Guild Migrate

Turn an agent built on another platform into a working Guild agent, with a written report of everything that did and did not map. The skill ports code and configuration; it never publishes.

Load the reference for the detected platform before porting:

- [references/vercel-eve.md](references/vercel-eve.md)
- [references/langchain.md](references/langchain.md) (LangChain, LangGraph, LangSmith, Fleet)
- [references/runlayer.md](references/runlayer.md)
- [references/arcade.md](references/arcade.md) (Arcade tools, toolkits, MCP Gateways)
- [references/guild-target.md](references/guild-target.md) for Guild primitives and CLI commands

## Workflow

1. **Detect.** Match the source directory against [Detection signals](#detection-signals). If two platforms match (for example a LangGraph agent behind a LiteLLM gateway), migrate the agent and treat the gateway as model configuration. Arcade is usually the *tool layer* under an agent built with another framework (such as LangChain, OpenAI Agents, Vercel AI SDK, or Mastra): migrate the agent with its framework's reference (or as plain code to TypeScript or Native) **and** map every Arcade tool with [references/arcade.md](references/arcade.md).
2. **Inventory.** List, by name only, every: tool, MCP server or connection, model and fallback, prompt or instructions file, sub-agent, schedule, webhook, channel (Slack, Teams, HTTP), approval point, memory or state store, environment variable, and secret. Never copy secret values into the new agent or the report.
3. **Choose the Guild agent type.** Apply these rules:
   - **Native** (`PROMPT.md` + `guild.yaml`) when instructions plus tools and text-in/text-out are enough.
   - **TypeScript** (`agent.ts`) for typed input/output, deterministic orchestration, or attachments.
   - **OpenClaw** (`AGENTS.md` + `skills/`) when the agent needs shell, file editing, git, or a repository.
   - **Goose** (`recipe.yaml`) for a portable recipe with parameters and an optional response schema.
   - **LangGraph** (`langgraph.json` + `graph.py`) for a Python LangGraph v1 graph that only needs `langchain`, `langchain-core`, `langchain-openai`, and `langgraph`.
   Record the reason in the report.
4. **Concept map.** Fill the concept-map table from the platform reference for this specific agent: one row per inventoried item, with the Guild target or `no equivalent`.
5. **Scaffold with the CLI.** Run `guild agent init --name <name> --agent-type <type> --category <category> --owner <owner>` in a new directory. Pass `--category` and `--owner` so the CLI doesn't prompt; list categories with `guild agent categories`. Use `--fork owner~agent` when a Hub agent is a better starting point. Never create or edit `guild.json` by hand.
6. **Port.** Move instructions first, then tools, then orchestration, then triggers. Keep pure logic in `logic.ts` (TypeScript) so it can be unit tested without `task`.
7. **Close integration gaps.** For each external service, check the Guild catalog with `guild integration list` and `guild integration operation list <owner~name> --json`. Register only the operations the agent calls. For an API with no integration, use `guild integration create` with an OpenAPI spec, then diff `operation list --json` against the spec.
8. **Test.** From the agent directory: `pnpm install && pnpm test`, then `git add -A`, then `guild agent test`. The scaffold has no `test` script, so add one before relying on `pnpm test`. If `pnpm install` fails with `ERR_PNPM_IGNORED_BUILDS`, run `pnpm approve-builds` and approve esbuild. `guild agent test` uploads only files git tracks, so without `git add -A` new files such as `logic.ts` are left out and the build fails with "Cannot find module". Send the same sample request the source agent handled and compare the outputs.
9. **Write `MIGRATION.md`** in the new agent directory using the template below.
10. **Stop.** Do not run `guild agent save --publish`, `guild agent publish`, `guild workspace agent add`, or `guild trigger create` unless the user asks. List them as next steps in the report.

## Detection signals

| Platform | Strong signals | Supporting signals |
|---|---|---|
| Vercel eve | `agent/instructions.md` plus `agent/agent.ts`; imports from `eve/tools`, `eve/connections`, `eve/schedules` | `agent/tools/*.ts`, `agent/subagents/*/agent.ts`, `agent/channels/`, `evals/**/*.eval.ts`, `eve` in `package.json` |
| LangGraph (Python) | `langgraph.json` with a `graphs` map; `from langgraph` / `from langchain.agents import create_agent` | `pyproject.toml` or `requirements.txt` with `langgraph`, `langchain`, `langsmith` |
| LangChain (JS) | `createAgent` from `langchain`; `@langchain/langgraph` in `package.json` | `@langchain/mcp-adapters`, `humanInTheLoopMiddleware`, `LANGSMITH_API_KEY` in `.env.example` |
| LangSmith Fleet | Exported Fleet agent description, or a user describing a no-code LangSmith agent | Tool list of Fleet connections (Gmail, Slack, Calendar, GitHub) |
| Runlayer | `runlayer_agent` Terraform resource, or the Runlayer agent fields (main prompt, connectors, model, skills, env vars) | `~/.runlayer/config.yaml`, or MCP client configs that call `runlayer run <server-id>` |
| Arcade | `arcade-mcp`, `arcade-mcp-server`, `arcadepy`, or `@arcadeai/arcadejs` dependencies; `from arcade_mcp_server import MCPApp`; `@app.tool(requires_auth=...)`; `client.tools.execute` | `eval_*.py` with `arcade_evals`, `ARCADE_API_KEY`, `api.arcade.dev/mcp/` URLs; legacy `arcade-tdk`, `arcade-ai`, `worker.toml`, `engine.yaml` |

## Hard rules

Applies to every TypeScript output. Native, Goose, OpenClaw, and LangGraph agents follow the `guild.yaml` rules in [references/guild-target.md](references/guild-target.md).

- Target the `@guildai/agents-sdk` 0.6 release line and `zod` `~4.3.0`. Do not copy `"*"` versions.
- Root `inputSchema` is `z.object({ ... })`. Put variants inside it, never as a root union.
- Runtime imports are limited to `@guildai/agents-sdk`, `zod`, `@guildai-services/*`, and relative local files (import sibling TypeScript with `.ts`; keep `rewriteRelativeImportExtensions: true`). Source-platform SDKs (`eve`, `langchain`, `litellm`, `ai`) do not ship in the Guild agent.
- No network egress at runtime. Every outside call goes through a Guild integration, `guildServiceTool`, or a sub-agent.
- `task.ui` needs `userInterfaceTools`; `task.guild` needs `guildTools`.
- Build `task.gather([...])` and `task.gatherSettled([...])` arrays inline.
- Slack: discover live schemas with `guild integration operation list guildai~slack --json`, then register only the needed operations with `guildServiceTool("slack", ...)`. Never import `slackTools`.
- Bound loops, payload sizes, LLM calls, and fan-out explicitly.
- Never hand-edit `guild.json`; never push an agent repository directly; save only through `guild agent save`.
- Never move secret values. Recreate credentials in Guild (`/platform/credentials`) and record only their names.

## Output: MIGRATION.md template

```markdown
# Migration: <source agent> → <owner~guild-agent>

- Source platform: <platform + version if known>
- Guild agent type: <type> — <one-line reason>
- Status: <ported and tested | ported, untested | partial>

## Concept map

| Source | Guild | Status |
|---|---|---|
| <tool / connection / schedule …> | <Guild target> | ported / stubbed / no equivalent |

## Integrations

| Service | Guild integration | Operations registered | Action needed |
|---|---|---|---|

## Credentials to create

| Name | Scope (account / workspace / member / agent) | Used by |
|---|---|---|

## Did not map 1:1

- <item>: <what changed and why>

## Test evidence

- Command: `guild agent test` with input: <sample>
- Result: <summary, and how it compares with the source agent>

## Next steps (not run)

- `guild agent save --message "<summary>" --wait --publish` (add `--force` on the first save after `guild agent init`)
- `guild workspace agent add <owner~agent> --workspace <owner~workspace>`
- `guild trigger create --workspace <owner~workspace> --type <time|webhook|api> --agent <owner~agent> …`
```

## What doesn't map 1:1

Each platform reference ends with a **Gaps** section. Copy the relevant gaps into the report rather than hiding them. The common ones:

- Per-tool approval policies (eve `approval`, Fleet "Ask", Runlayer guarded calls) become two controls: a credential policy scoped to the agent and workspace (who can call it) plus a `ui_prompt` confirmation before the call (sign-off on each call; the run pauses until someone answers). List the policy rules under Next steps.
- Guild is hosted only. Self-hosted source deployments move to Guild's runtime.
- Source eval suites do not run on Guild unchanged. Rebuild them as Guild Evaluations or `guild agent test` cases.
- Per-end-user OAuth for your own app's customers (Arcade `user_id`) has no Guild equivalent; Guild credentials belong to Guild members, workspaces, or agents.
````

> [accordion] references/vercel-eve.md
>
> Vercel eve
>
> ````markdown guild-migrate/references/vercel-eve.md theme={null}
> # Vercel eve → Guild
>
> eve is Vercel's open-source (Apache-2.0), filesystem-first TypeScript framework for durable agents, in beta as of 2026-10-27. An eve agent is the `agent/` directory (or `agents/<name>/agent/` in a multi-agent workspace): every file is a slot the framework discovers.
>
> Sources: https://vercel.com/docs/eve, https://eve.dev/docs/reference/agent-files, https://eve.dev/docs/tools.md, https://eve.dev/docs/connections, https://eve.dev/docs/schedules.md
>
> ## Detection signals
>
> - `agent/instructions.md` (or `instructions.ts`, or an `instructions/` directory) and `agent/agent.ts` (`defineAgent`).
> - `agent/tools/*.ts` importing `defineTool` from `eve/tools`.
> - `agent/connections/*.ts` importing from `eve/connections`.
> - `agent/schedules/*.ts|*.md`, `agent/channels/`, `agent/subagents/` (directories or single files), `agent/skills/`, `agent/sandbox.ts` or `agent/sandbox/`, `agent/memory.ts` or `agent/memory/`, `agent/hooks/`.
> - `evals/**/*.eval.ts`; `eve` in `package.json` dependencies or scripts (`eve dev`, `eve deploy`).
>
> ## Choosing the Guild type
>
> Every eve agent has a sandbox, and the built-in `bash`, `read_file`, and `write_file` tools are on unless `agent.ts` sets `defaultTools: false`. Decide by whether the agent's instructions or tools actually rely on them:
>
> - Tools plus instructions, no shell or file work → **Native** if text in/out is enough, otherwise **TypeScript** (`llmAgent` for prompt-driven, `agent` for code-driven).
> - Relies on `bash`, `read_file`, or `write_file`, customizes `agent/sandbox.ts` or `agent/sandbox/`, or works on a repository → **OpenClaw**.
> - Mostly deterministic `run` code with typed I/O → **TypeScript** `agent`.
>
> ## Concept map
>
> | eve | Guild |
> |---|---|
> | `agent/instructions.md` | `PROMPT.md` (Native), `AGENTS.md` (OpenClaw), or `systemPrompt` (TypeScript `llmAgent`) |
> | `agent/agent.ts` `defineAgent({ model })` | `guild.yaml` `models` fallback list, or account LLM settings for TypeScript |
> | `agent/tools/<name>.ts` `defineTool` | Guild integration operation via `pick(...)`, or a pure function in `logic.ts` called from `run` |
> | `agent/connections/*` `defineMcpClientConnection` / `defineOpenAPIConnection` | Guild integration (`guild integration create` from the OpenAPI spec or MCP server) |
> | Connection `auth: { getToken }`, Vercel Connect OAuth | Guild credential (account / workspace / member / agent scope) behind the credential proxy |
> | `agent/subagents/<name>/` | Separate Guild agent called with `guildAgentTool({ calls: "owner~agent" })`, or `sub_agents` in `guild.yaml` |
> | `agent/skills/` | OpenClaw `skills/<name>/SKILL.md`, or Guild Hub skills |
> | `agent/schedules/*` `defineSchedule({ cron })` | `guild trigger create --type time` |
> | `agent/channels/` HTTP | `guild trigger create --type api` |
> | `agent/channels/` Slack, GitHub, Linear | `guild trigger create --type webhook --integration <slack|github|linear> --event …` |
> | Tool `approval: always()` / `once()` | Credential policy scoped to the agent (who can call it) plus a `ui_prompt` confirmation (sign-off on each call) |
> | Built-in `bash`, `read_file`, `write_file`; `agent/sandbox.ts` or `agent/sandbox/` | OpenClaw built-in shell, files, and git |
> | `agent/memory/` | `task.save` / `task.restore` (TypeScript), or `MEMORY.md` (OpenClaw, read-only per task) |
> | `evals/**/*.eval.ts` | Guild Evaluations (`/platform/evaluations`) and `guild agent test` cases |
> | Agent Runs dashboard, OpenTelemetry | Guild session event log, Insights, Spend Explorer |
> | `eve deploy` | `guild agent save --wait --publish` + `guild workspace agent add` |
>
> ## Before / after: a tool with approval
>
> eve (`agent/tools/refund.ts`):
>
> ```ts
> import { defineTool } from "eve/tools";
> import { always } from "eve/tools/approval";
> import { z } from "zod";
>
> export default defineTool({
>   description: "Refund a Stripe charge.",
>   inputSchema: z.object({ chargeId: z.string(), amountCents: z.number().int().positive() }),
>   approval: always(),
>   async execute({ chargeId, amountCents }) {
>     return stripe.refunds.create({ charge: chargeId, amount: amountCents });
>   },
> });
> ```
>
> Guild TypeScript (`agent.ts`, abbreviated). The refund goes through a Guild integration, and the sign-off becomes an explicit `ui_prompt` confirmation that pauses the run. A credential policy scoped to this agent controls which agents can call the refund operation at all:
>
> ```ts
> "use agent";
> import { agent, pick, userInterfaceTools, type Task } from "@guildai/agents-sdk";
> import { StripeTools } from "@guildai-services/<owner>~stripe"; // from `guild integration list`
> import { z } from "zod";
>
> const inputSchema = z.object({ chargeId: z.string().max(100), amountCents: z.number().int().positive().max(1_000_000) });
> const outputSchema = z.object({ status: z.enum(["refunded", "declined"]), refundId: z.string().optional() });
> const tools = { ...pick(StripeTools, ["stripe_refunds_create"]), ...pick(userInterfaceTools, ["ui_prompt"]) };
>
> async function run(input: z.infer<typeof inputSchema>, task: Task<typeof tools>) {
>   const answer = await task.tools.ui_prompt({
>     type: "text",
>     text: `Refund ${input.amountCents / 100} on ${input.chargeId}? Reply "yes" to approve.`,
>   });
>   if (!/^\s*yes\b/i.test(answer.text)) return { status: "declined" as const };
>   const refund = await task.tools.stripe_refunds_create({ charge: input.chargeId, amount: input.amountCents });
>   return { status: "refunded" as const, refundId: refund.id };
> }
>
> export default agent({ description: "Refunds a charge after a human approves it.", inputSchema, outputSchema, tools, run });
> ```
>
> Check the real tool name and parameter shape with `guild integration operation list <owner~stripe> --json`; the names above are illustrative.
>
> ## Before / after: a schedule
>
> eve (`agent/schedules/digest.ts`):
>
> ```ts
> import { defineSchedule } from "eve/schedules";
> export default defineSchedule({ cron: "0 8 * * 1", content: "Summarize last week's open Linear issues." });
> ```
>
> Guild:
>
> ```bash
> guild trigger create --workspace <owner~workspace> --type time --agent <owner~agent> \
>   --frequency WEEKLY --time 08:00 --days-of-week MONDAY \
>   --input '{"type":"text","text":"Summarize last week'"'"'s open Linear issues."}'
> ```
>
> ## Pitfalls
>
> - eve tool files often call vendor SDKs or `fetch` directly. Guild runtime has no network egress: replace each call with an integration operation.
> - eve tool names are file names; Guild tool names come from the integration (`{service}_{operation}`). Update prompts that mention tool names.
> - `defineDynamic` per-tenant connections → member-scoped credentials plus identity mapping, not code.
> - eve schedules run in UTC on Vercel Cron. Guild `CRON` triggers take the same expression plus an optional `--cron-timezone`, and Guild converts the schedule to UTC.
>
> ## Gaps
>
> - Tool approvals become a credential policy scoped to the agent and workspace (who can call it) plus a `ui_prompt` confirmation before the call (sign-off on each call; the run pauses until someone answers).
> - eve can self-host as a Node service; Guild is hosted only.
> - eve evals (`defineEval`, with Braintrust, JUnit, or Datadog reporters) do not run on Guild; rebuild key cases as Guild Evaluations.
> - eve channels such as Twilio (SMS and phone calls), iMessage through Linq or Photon, Discord, Microsoft Teams, or Telegram have no direct Guild trigger; check `guild integration list` first.
> ````

> [accordion] references/langchain.md
>
> LangChain, LangGraph, LangSmith, and Fleet
>
> ````markdown guild-migrate/references/langchain.md theme={null}
> # LangChain, LangGraph, LangSmith → Guild
>
> LangChain and LangGraph are open-source agent libraries (Python and JS). LangChain v1 provides `createAgent` / `create_agent`; LangGraph is the graph and durable-state runtime. LangSmith is the commercial platform: tracing, evals, Deployment (formerly LangGraph Platform), and Fleet (the no-code agent builder, formerly Agent Builder). Facts as of 2026-10-27.
>
> Sources: https://docs.langchain.com/oss/javascript/langchain/agents, https://docs.langchain.com/langsmith/cli, https://docs.langchain.com/langsmith/fleet, https://docs.langchain.com/langsmith/deployment, https://docs.guild.ai/guide/langgraph-agents.md
>
> ## Detection signals
>
> - `langgraph.json` with `graphs`, `dependencies`, `env`.
> - Python: `from langchain.agents import create_agent`, `from langgraph.graph import StateGraph`; MCP through `langchain_mcp_adapters` (archived) or `from langchain.mcp import MCPAdapter` (`langchain[mcp]`); `langgraph` / `langchain` / `langsmith` in `pyproject.toml` or `requirements.txt`.
> - JS: `createAgent` from `langchain`; `@langchain/langgraph`, `@langchain/mcp-adapters` in `package.json`.
> - `LANGSMITH_API_KEY` / `LANGSMITH_TRACING` (or the legacy `LANGCHAIN_API_KEY` / `LANGCHAIN_TRACING_V2`) in `.env.example`.
> - Fleet: a no-code agent description, its connections list, and its triggers (Slack, Teams, Gmail, Outlook, schedule, webhook).
>
> ## Three paths
>
> ### Path A: Python LangGraph → Guild LangGraph agent (closest port)
>
> Guild runs LangGraph v1 graphs directly. Keep the graph; swap the model and tools.
>
> Constraints: Python 3.13; only `langchain`, `langchain-core`, `langchain-openai`, `langgraph`, and `guildai_langchain` are installed; no other pip packages; no general network access; `langgraph.json` targets must be relative `.py` paths (`./graph.py:graph`); convert module paths such as `pkg.mod:graph` to `./pkg/mod.py:graph`.
>
> Before (`graph.py`):
>
> ```python
> from langchain.agents import create_agent
> from langchain_anthropic import ChatAnthropic
> from langchain_mcp_adapters.client import MultiServerMCPClient
>
> client = MultiServerMCPClient({"github": {"url": "https://mcp.example.com/github", "transport": "streamable_http"}})
>
> async def graph():
>     tools = await client.get_tools()
>     return create_agent(ChatAnthropic(model="claude-sonnet-5-5"), tools, system_prompt="Triage new GitHub issues.")
> ```
>
> After (`graph.py`), with tools declared in `guild.yaml`:
>
> ```python
> from guildai_langchain import guild_model, guild_tools
> from langchain.agents import create_agent
>
> async def graph():
>     return create_agent(guild_model(), await guild_tools(), system_prompt="Triage new GitHub issues.")
> ```
>
> ```json
> { "dependencies": ["."], "graphs": { "agent": "./graph.py:graph" } }
> ```
>
> ```yaml
> # guild.yaml
> integrations:
>   - name: guildai~github
>     version: ^1.0.0
>     tools: [github_issues_list_for_repo, github_issues_update]
> ```
>
> Steps: `guild agent init --name <name> --agent-type LANGGRAPH --category <category> --owner <owner>`, replace the scaffold `graph.py`, move tool access into `guild.yaml`, remove provider packages (`langchain-anthropic`, `langchain-mcp-adapters` or `langchain[mcp]`) and their API keys, then `git add -A` and `guild agent test`.
>
> ### Path B: JS `createAgent` → Guild TypeScript
>
> ```ts
> // before
> import { createAgent, humanInTheLoopMiddleware } from "langchain";
> const agent = createAgent({
>   model: "anthropic:claude-sonnet-5-5",
>   tools: [searchDocs, createTicket],
>   systemPrompt: "Answer support questions; open a ticket when you cannot.",
>   middleware: [humanInTheLoopMiddleware({ interruptOn: { create_ticket: true } })],
> });
> ```
>
> ```ts
> // after (agent.ts)
> "use agent";
> import { llmAgent, pick, userInterfaceTools } from "@guildai/agents-sdk";
> import { ZendeskTools } from "@guildai-services/<owner>~zendesk"; // from `guild integration list`
>
> export default llmAgent({
>   description: "Answers support questions and opens a ticket, after confirmation, when it cannot.",
>   tools: { ...pick(ZendeskTools, ["zendesk_search", "zendesk_tickets_create"]), ...pick(userInterfaceTools, ["ui_prompt"]) },
>   systemPrompt: "Answer support questions. Before creating a ticket, ask the user to confirm with ui_prompt.",
>   mode: "multi-turn",
> });
> ```
>
> Use `agent({ ..., run })` instead of `llmAgent` when the graph has deterministic branches; each LangGraph node becomes a function, edges become ordinary control flow, and parallel branches become an inline `task.gather([...])`.
>
> ### Path C: LangSmith Fleet → Guild Native
>
> Fleet agents are instructions plus connections plus triggers. Port them to `PROMPT.md` + `guild.yaml` (`guild agent init --name <name> --agent-type GUILD_NATIVE --category <category> --owner <owner>`), then recreate triggers with `guild trigger create`. For each tool set to "Ask", add the `ui` built-in with `ui_prompt` and tell the agent to confirm before calling it. Fleet "Claws" (fixed credentials) → workspace- or agent-scoped credentials; Fleet "Assistants" and per-user connections (act as the invoker) → member-scoped credentials with identity mapping.
>
> ## Concept map
>
> | LangChain / LangGraph / LangSmith | Guild |
> |---|---|
> | `create_agent` / `createAgent` | LangGraph agent (Python) or `llmAgent` (TypeScript) |
> | `StateGraph` nodes and edges | LangGraph agent unchanged, or TypeScript `agent` `run` control flow |
> | Model string (`anthropic:…`) | `guild_model()` (Python) / `guild.yaml` `models` / account LLM settings |
> | Tools (`@tool`, MCP adapters) | Guild integrations declared in `guild.yaml` or `pick(...)` |
> | `humanInTheLoopMiddleware`, `interrupt()` | `ui_prompt` / `task.tools.ui_prompt` confirmation (sign-off on each call), plus a credential policy scoped to the agent (who can call it) |
> | Checkpointer, thread state | Guild session state; `task.save` / `task.restore` in TypeScript |
> | `langgraph.json` `env` | Guild credentials (never `.env` values) |
> | LangSmith tracing | Guild session event log (`GET /v1/sessions/{id}/events`), Insights |
> | LangSmith datasets and evaluators | Guild Evaluations and `guild agent test` |
> | LangSmith Deployment cron jobs | `guild trigger create --type time` |
> | Agent Server API (`runs` endpoints) | `guild trigger create --type api` |
> | Run webhooks (POST callback when a run finishes) | No trigger equivalent; have the agent call your service through an integration as its last step |
> | Fleet Slack, Teams, Gmail, Outlook triggers | `guild trigger create --type webhook --integration <slack|gmail|…> …` |
> | Fleet schedules | `guild trigger create --type time` |
> | Fleet sharing (clone / run / edit) | Hub visibility (Draft, Internal, Public) and workspaces |
> | `langgraph deploy` | `guild agent save --wait --publish` |
>
> ## Pitfalls
>
> - Legacy APIs: `AgentExecutor` moved to `langchain-classic` in v1, which Guild's runtime does not install, and `langgraph.prebuilt.create_react_agent` is deprecated since v1. Upgrade to `create_agent` first.
> - Any extra Python dependency (vector store clients, `requests`, provider SDKs) blocks Path A. Replace it with a Guild integration or move to TypeScript.
> - `guild_tools()` is async, so the graph target must be an async factory.
> - A LangGraph turn fails after 10 minutes without events; long-running nodes must call Guild tools or be split.
>
> ## Gaps
>
> - Guild's LangGraph runtime is Python only and allows no extra packages; LangSmith Deployment allows arbitrary dependencies.
> - LangSmith Deployment can self-host or run hybrid; Guild is hosted only.
> - LangSmith evaluators, datasets, and Engine failure clustering have no 1:1 equivalent; port the key cases to Guild Evaluations.
> - `interruptOn` and Fleet "Ask" become a credential policy scoped to the agent and workspace (who can call it) plus a `ui_prompt` confirmation before the call (sign-off on each call; the run pauses until someone answers).
> ````

> [accordion] references/runlayer.md
>
> Runlayer
>
> ````markdown guild-migrate/references/runlayer.md theme={null}
> # Runlayer → Guild
>
> Runlayer is a commercial, proprietary enterprise AI control plane: MCP Gateway, Catalog, Runtime Security, Agent IAM & Governance, ROI & Observability, Shadow AI, and **Runlayer Agents** (governed agents created in its UI or from clients such as Slack, Microsoft Teams, Claude, Cursor, ChatGPT, and Codex). Facts as of 2026-10-27.
>
> Sources: https://runlayer.com/llms.txt, https://docs.runlayer.com/llms.txt, https://docs.runlayer.com/platform-agents.md, https://docs.runlayer.com/platform-agent-accounts.md, https://docs.runlayer.com/platform-agents.md#human-in-the-loop-approvals, https://docs.runlayer.com/platform-agents-terraform.md, https://docs.runlayer.com/deployment/overview.md
>
> ## Detection signals
>
> Runlayer agents live in Runlayer, not in a repository, so the input is usually one of:
>
> - A `runlayer_agent` Terraform resource. It covers the prompt, model, connectors and tools, skills, env var names, and built-in tools, but not triggers, sharing, or approvals, and edits made in the app don't show up as drift. Read those from the agent's page in the app.
> - The agent's fields copied from the UI: name, main prompt, privacy, built-in tools (memory, code mode), MCP connectors with selected tools, model, instructions, skills, env vars.
> - Its triggers (cron schedule, webhook, API, Slack mention or channel monitor, Microsoft Teams, iMessage, audit-event trigger) and approvals.
> - Subagents and allowed agents, the network access policy, GitHub access, and memory (workbench memory and scoped `remember`/`forget` memory).
>
> Ask the user for these fields if they are not in the workspace. Never ask for secret values.
>
> ## Choosing the Guild type
>
> Every Runlayer agent runs in a sandbox with shell, file, and browser tools, so decide by what the prompt relies on:
>
> - Text in/out with tools → **Native** (`PROMPT.md` + `guild.yaml`).
> - Code mode turned on, or a prompt that relies on shell commands, files in `/tmp/workspace`, the built-in or cloud browser, or GitHub access → **OpenClaw** (browser work also needs a browser integration).
> - Needs typed I/O or deterministic steps → **TypeScript**.
>
> ## Concept map
>
> | Runlayer | Guild |
> |---|---|
> | Main prompt + instructions | `PROMPT.md` (Native) or `AGENTS.md` (OpenClaw) |
> | Model (Anthropic, OpenAI, Bedrock, Azure Foundry, Google AI Studio, OpenAI-compatible) | `guild.yaml` `models` fallback list |
> | MCP connectors with per-tool selection | `guild.yaml` `integrations` with a `tools` list |
> | Catalog / MCP Gateway servers | Guild integrations (catalog, `guild integration create`) |
> | Skills | OpenClaw `skills/<name>/SKILL.md`, or Guild Hub skills |
> | Env vars | Guild credentials (secrets) or workspace variables for settings (`guild workspace variable set KEY=value --workspace <owner~workspace>`) |
> | Built-in memory | OpenClaw `MEMORY.md` (read-only per task) or TypeScript `task.save` / `task.restore` |
> | Code mode / sandbox | OpenClaw shell, files, git |
> | Cron schedule | `guild trigger create --type time --frequency CRON --cron-expression "<expr>" --cron-timezone <tz>` (converted to UTC) |
> | Webhook trigger | `guild trigger create --type webhook` (integration events) or `--type api` |
> | Slack mention | `guild trigger create --type webhook --integration slack --event app_mention` |
> | Slack channel monitor (new top-level messages, optional semantic condition) | `guild trigger create --type webhook --integration slack --event message`, with the Slack agent invited to the monitored channels |
> | Agent Accounts (on-behalf-of or machine-to-machine) | Member-scoped credentials + identity mapping, or agent-scoped credentials |
> | Policies (server, tool, user, group, arguments) | Credential policies (ALLOW/DENY by operation, resource, agent, workspace) |
> | Guarded tool calls (requester approves) | Credential policy scoped to the agent (who can call it) plus a `ui_prompt` confirmation (sign-off on each call) |
> | Versioning on every save | `guild agent save` versions with semver (`--bump`) |
> | Sharing (Can use / Can edit) | Workspaces and Hub visibility (Draft, Internal, Public) |
> | Sessions, cost, budgets | Session event log, Spend Explorer, spend budgets |
> | Agent Evals (replay with another model or prompt) | Guild Evaluations, `guild agent test` |
>
> ## Before / after
>
> Runlayer agent (fields):
>
> ```text
> Name: Incident scribe
> Main prompt: When an incident channel opens, collect the timeline from Slack and PagerDuty and draft a postmortem in Notion.
> Connectors: Slack (conversations.history), PagerDuty (incidents.get), Notion (pages.create)
> Model: Claude
> Trigger: Slack channel monitor on #incidents
> ```
>
> Guild Native agent:
>
> ```markdown
> <!-- PROMPT.md -->
> You are Incident scribe. When asked about an incident, collect the timeline from the Slack channel
> and the PagerDuty incident, then draft a postmortem page in Notion. Ask before creating the page.
> ```
>
> ```yaml
> # guild.yaml
> models:
>   - provider: anthropic
> integrations:
>   - name: <owner>~pagerduty
>     version: ^1.0.0
>     tools: [pagerduty_incidents_get]
>   - name: <owner>~notion
>     version: ^1.0.0
>     tools: [notion_pages_create]
> builtins:
>   - name: ui
>     tools: [ui_prompt]
> ```
>
> Slack history access depends on the live Slack integration schema; check `guild integration operation list guildai~slack --json`. Then:
>
> ```bash
> guild agent init --name incident-scribe --agent-type GUILD_NATIVE --category <category> --owner <owner>
> guild workspace variable set INCIDENT_CHANNEL=incidents --workspace <owner~workspace>
> git add -A
> guild agent test
> ```
>
> ## Pitfalls
>
> - Runlayer connectors are MCP servers; Guild integrations are versioned packages with `{service}_{operation}` tool names. Map each selected tool explicitly.
> - Runlayer schedules can run on local wall-clock time and as the schedule's creator; Guild triggers run with the credentials resolved for the workspace and agent. Re-check whose identity each action uses.
> - Runlayer `schedule_continuation` (wait 1 minute to 24 hours) has no direct Guild equivalent; split into a scheduled trigger.
>
> ## Gaps
>
> - Runlayer offers customer-hosted runtimes (ECS or Kubernetes); Guild is hosted only.
> - Runlayer's ToolGuard/AgentGuard runtime scanners, Shadow AI discovery, and argument-level policies go beyond Guild credential policies. Both restrict egress: Runlayer with a per-agent network access policy, Guild by cutting container network access so only Guild proxies reach out.
> - Microsoft Teams and iMessage triggers have no Guild trigger; check `guild integration list` first.
> - Requester-only approvals with expiry windows (a pending request lapses after 24 hours) have no direct equivalent. Use a credential policy scoped to the agent and workspace (who can call it) plus a `ui_prompt` confirmation before the call (sign-off on each call; the run pauses until someone answers).
> - Audit-event triggers with semantic conditions have no Guild equivalent.
> ````

> [accordion] references/arcade.md
>
> Arcade tools, toolkits, and MCP Gateways
>
> ````markdown guild-migrate/references/arcade.md theme={null}
> # Arcade → Guild
>
> Arcade (arcade.dev) is an "actions runtime" for AI agents: per-user OAuth for tools, a catalog of more than 100 integrations, MCP Gateways, tool-level policy hooks, an admin audit log, and `arcade evals` for tool selection. Tools are written in Python with the MIT-licensed `arcade-mcp` framework (`MCPApp`, `@app.tool(requires_auth=...)`). Arcade has **no agent runtime**: no hosted agents, sessions, triggers, schedules, or agent hub. Agents that use Arcade are built in another framework (such as LangChain, OpenAI Agents, Vercel AI SDK, Mastra, Google ADK, CrewAI, AG2, CopilotKit, or Spring AI) and call Arcade through `arcadepy` / `@arcadeai/arcadejs` or an MCP Gateway. Facts as of 2026-10-27.
>
> Sources: https://www.arcade.dev/, https://docs.arcade.dev/llms.txt, https://github.com/ArcadeAI/arcade-mcp, https://docs.arcade.dev/en/references/mcp/python, https://docs.arcade.dev/en/references/auth-providers, https://docs.arcade.dev/en/operate/governance/mcp-gateways, https://docs.arcade.dev/en/operate/governance/contextual-access, https://docs.arcade.dev/en/resources/integrations, https://docs.arcade.dev/en/references/arcade-cli, https://www.arcade.dev/pricing
>
> So an Arcade migration has two halves. Migrate the **agent** using the reference for its framework (`vercel-eve.md`, `langchain.md`, or plain code → TypeScript/Native). Map the **tools** with this reference.
>
> ## Detection signals
>
> | Strength | Signal |
> |---|---|
> | Strong | `arcade-mcp`, `arcade-mcp-server`, or `arcadepy` in `pyproject.toml` / `requirements.txt`; `@arcadeai/arcadejs` in `package.json` |
> | Strong | `from arcade_mcp_server import MCPApp, Context`; `@app.tool(requires_auth=GitHub())`; `requires_secrets=[...]` |
> | Strong | `client.tools.execute(...)`, `client.tools.authorize(...)`, `client.auth.wait_for_completion(...)` / `waitForCompletion` |
> | Supporting | `eval_*.py` importing `arcade_evals`; `ARCADE_API_KEY`, `ARCADE_BASE_URL`, `ARCADE_URL` in `.env.example`; `https://api.arcade.dev/mcp/<slug>` URLs; `Arcade-User-ID` header |
> | Legacy | `arcade-tdk`, `arcade-ai`, `arcade-serve`, `langchain-arcade`, `agents-arcade` (deprecated or unmaintained); `from arcade_tdk import tool, ToolContext`; `worker.toml`; `engine.yaml` |
>
> ## Two migration paths
>
> - **A. Replace Arcade.** Each Arcade toolkit becomes a Guild integration; custom `MCPApp` tools become a custom Guild integration; the agent runs on Guild. Choose this when the toolkits in use exist in the Guild catalog or can be added with `guild integration create`.
> - **B. Keep Arcade as the tool layer.** Move only the agent to Guild and reach the Arcade MCP Gateway through a custom integration. **Verify first** that a Guild custom integration can front a remote Streamable HTTP MCP server. The gateway must use the **Arcade Headers** auth mode, which takes `Authorization: Bearer <API key>` and `Arcade-User-ID: <end user>`; the other modes (Arcade Auth, User Source) need a browser OAuth flow. Choose this when the agent depends on Arcade-only toolkits or per-end-user OAuth that Guild credentials do not cover.
>
> ## Concept map
>
> | Arcade | Guild |
> |---|---|
> | Prebuilt toolkit (Gmail, Slack, GitHub, Linear, Notion, Google Calendar, …) | Guild integration from the catalog (`guild integration list`), tools named `{service}_{operation}` |
> | Custom `MCPApp` server / `@app.tool` | Custom integration: `guild integration create` from an OpenAPI spec or MCP server |
> | `requires_auth=<Provider>()` (per-user OAuth) | Integration credential; member-scoped for per-person access, plus identity mapping for Slack/GitHub-started runs |
> | `requires_secrets=[...]` / `context.get_secret` | Guild credentials (the proxy injects them; the agent never sees values) or workspace variables |
> | `user_id` passed per call | The Guild member or agent whose credential resolves for the session |
> | `client.tools.authorize` + `wait_for_completion` (connect prompt) | Connect the credential in Guild once; the proxy injects it on every call |
> | `client.tools.execute(tool_name=..., input=...)` in an agent loop | TypeScript `pick(<Integration>Tools, [...])` / `guildServiceTool(...)`, or `guild.yaml` `integrations` with a `tools` list |
> | MCP Gateway (`api.arcade.dev/mcp/<slug>`) | Path A: integrations declared on the agent. Path B: a custom integration fronting the gateway (verify) |
> | Contextual Access hooks (allow, deny, modify, redact) | Credential policies (ALLOW/DENY by operation, resource, agent, workspace); modify/redact has no equivalent |
> | Tool grant / revoke / versioning | Integration versions pinned with semver ranges in `guild.yaml` or `package.json` |
> | `arcade evals` (`eval_*.py`, `EvalSuite`, critics) | Guild Evaluations (`hasToolCall`, `toolCallContains`, `outputMatches`, `llmJudge`) and `guild agent test` |
> | Tool execution records, admin audit log (REST API) | Session event log and the org audit log |
> | `arcade deploy` (host an MCP server) | No equivalent: Guild hosts agents and brokers integrations, not arbitrary MCP servers |
> | Self-hosted (cloud marketplace, Helm, VPC, air-gapped) | No equivalent: Guild is hosted only |
>
> ## Before / after: custom tool with `requires_auth`
>
> Arcade `MCPApp` server:
>
> ```python
> from typing import Annotated
> from arcade_mcp_server import Context, MCPApp
> from arcade_mcp_server.auth import GitHub
>
> app = MCPApp(name="triage_tools", version="1.0.0")
>
> @app.tool(requires_auth=GitHub(scopes=["repo"]))
> async def comment_on_issue(
>     context: Context,
>     owner: Annotated[str, "Repository owner"],
>     repo: Annotated[str, "Repository name"],
>     issue_number: Annotated[int, "Issue number"],
>     body: Annotated[str, "Comment text"],
> ) -> dict:
>     """Post a triage comment on a GitHub issue."""
>     token = context.get_auth_token_or_empty()
>     ...  # httpx POST to api.github.com with the token
> ```
>
> Guild TypeScript agent: the GitHub integration replaces the tool, and Guild injects the credential.
>
> ```ts
> "use agent";
> import { gitHubTools } from "@guildai-services/guildai~github";
> import { agent, pick, type Task } from "@guildai/agents-sdk";
> import { z } from "zod";
>
> const inputSchema = z.object({
>   owner: z.string(),
>   repo: z.string(),
>   issueNumber: z.number().int().positive(),
>   body: z.string().max(4_000),
> });
> const outputSchema = z.object({ commented: z.boolean() });
> const tools = { ...pick(gitHubTools, ["github_issues_create_comment"]) };
>
> async function run(input: z.infer<typeof inputSchema>, task: Task<typeof tools>) {
>   await task.tools.github_issues_create_comment({
>     owner: input.owner,
>     repo: input.repo,
>     issue_number: input.issueNumber,
>     body: input.body,
>   });
>   return { commented: true };
> }
>
> export default agent({
>   description: "Posts a triage comment on a GitHub issue.",
>   inputSchema,
>   outputSchema,
>   tools,
>   run,
> });
> ```
>
> Check the exact operation input shape with `guild integration operation list guildai~github --json` before porting.
>
> ## Before / after: agent calling Arcade tools
>
> Agent loop with `arcadepy` (OpenAI Agents or LangChain wraps the same calls):
>
> ```python
> from arcadepy import Arcade
>
> client = Arcade()  # ARCADE_API_KEY
> auth = client.tools.authorize(tool_name="Gmail.ListEmails", user_id=user_email)
> if auth.status != "completed":
>     print("Authorize:", auth.url)
>     client.auth.wait_for_completion(auth.id)
> emails = client.tools.execute(
>     tool_name="Gmail.ListEmails", input={"n_emails": 10}, user_id=user_email
> ).output.value
> ```
>
> Guild Native agent:
>
> ```markdown
> <!-- PROMPT.md -->
> You summarize the user's latest emails. List the 10 most recent messages, group them by sender,
> and flag anything that needs a reply today.
> ```
>
> ```yaml
> # guild.yaml
> models:
>   - provider: anthropic
> integrations:
>   - name: guildlabs~gmail-oauth
>     version: ^1.0.1
>     tools: [gmail_oauth_users_messages_list, gmail_oauth_users_threads_get]
> ```
>
> Native agents support only the `ui` built-in, so there is no connect step in the agent. Connect the Gmail credential in Guild once.
>
> The Gmail integration and tool names above are the ones used by Guild agents in this repository today. Confirm them with `guild integration list` and `guild integration operation list guildlabs~gmail-oauth --json`. Then:
>
> ```bash
> guild agent init --name inbox-digest --agent-type GUILD_NATIVE --category <category> --owner <owner>
> git add -A
> guild agent test
> ```
>
> ## Pitfalls
>
> - In late October 2026, Arcade Cloud started running a release (previewed as 1.12.0) that renamed tools across most toolkits, with no aliases. Self-hosted installs get it in the next release. Map from the tool names the source code actually calls, not from current Arcade docs.
> - Arcade's `user_id` is your app's end user; Guild credentials belong to Guild members, workspaces, or agents. A multi-tenant SaaS that authorizes thousands of its own customers through Arcade does not map to member-scoped credentials. Keep Arcade for that layer (path B) or redesign.
> - Arcade Contextual Access can modify or redact tool inputs and outputs; Guild credential policies only allow or deny. Move modify/redact logic into the agent code.
> - Arcade-managed OAuth apps are for development. Guild integrations use their own OAuth apps; users reconnect once in Guild.
> - Python `MCPApp` tool code does not run inside a Guild agent. Rewrite the call against an integration, or publish the API as a custom integration (`guild integration create`).
> - Catalog gaps: when no Guild integration exists for an Arcade toolkit, create one from the vendor's OpenAPI spec and diff `guild integration operation list --json` against the spec.
>
> ## Gaps
>
> - No per-end-user OAuth for your own app's customers; Guild authorizes Guild members.
> - No hosting of arbitrary MCP servers (`arcade deploy`).
> - No self-hosted, cloud marketplace, VPC, or air-gapped deployment; Guild is hosted only.
> - No modify/redact policy hooks on tool calls.
> - No Tool Recommendation or MCP Gateway-style tool search across a large catalog.
> - `arcade evals` suites do not run on Guild; rebuild them as Guild Evaluations.
> ````

> [accordion] references/guild-target.md
>
> Guild primitives and CLI commands
>
> ````markdown guild-migrate/references/guild-target.md theme={null}
> # Guild target: primitives and CLI
>
> The Guild side of every migration. Facts from docs.guild.ai and Guild CLI 0.27.2 and 0.28.0, as of 2026-10-23.
>
> ## Agent types
>
> | Type | Files | Runtime | Pick it when |
> |---|---|---|---|
> | Native | `PROMPT.md`, `guild.yaml` | No container; ready immediately | Instructions plus tools, text in and text out |
> | TypeScript | `agent.ts`, `package.json`, `tsconfig.json` (`guild.json` is CLI-managed) | Built and validated on save | Typed input/output, deterministic orchestration, attachments |
> | Goose | `recipe.yaml`, `guild.yaml` | Container (`guildai~goosebox` by default) | Portable recipe with parameters and a response schema |
> | OpenClaw | `AGENTS.md`, `guild.yaml`, optional `skills/<name>/SKILL.md`, `IDENTITY.md`, `USER.md`, `SOUL.md`, `MEMORY.md` | `guildai~lobsterpot` container with shell, file editing, git, search | Repository, file, or command work |
> | LangGraph | `langgraph.json`, `graph.py`, `guild.yaml` | Python 3.13 container with `langchain`, `langchain-core`, `langchain-openai`, `langgraph`, `guildai_langchain` | A LangChain/LangGraph v1 graph with no extra pip packages |
>
> Constraints that matter during a port:
>
> - Native: no container, no filesystem, no custom input or output schemas, no attachments. Built-ins are `ui_prompt` and `ui_progress`.
> - OpenClaw: the workspace is rebuilt from committed files on every task, so writes do not persist between tasks.
> - LangGraph: no general network access; no extra packages; `AgentExecutor` is not installed (it moved to `langchain-classic`) and `create_react_agent` is deprecated, so use `create_agent`; a turn fails after 10 minutes without events (the clock pauses during Guild tool calls).
> - Every type: tool names must be unique across integrations, sub-agents, and builtins; a public agent cannot depend on a private integration or sub-agent.
>
> Sources: https://docs.guild.ai/guide/agent-types.md, https://docs.guild.ai/guide/native-agents.md, https://docs.guild.ai/guide/openclaw-agents.md, https://docs.guild.ai/guide/langgraph-agents.md
>
> ## `guild.yaml` (Native, Goose, OpenClaw, LangGraph)
>
> TypeScript agents do not use `guild.yaml`.
>
> ```yaml
> models:                     # ordered fallback list, max 16; first allowed entry wins
>   - provider: anthropic
>     model: claude-sonnet-5
>   - provider: openai        # omit model to accept any model from the provider
> integrations:
>   - name: acme~github
>     version: ^1.4.0
>     tools: [github_repos_get, github_issues_list_for_repo]   # omit to allow every operation
> sub_agents:
>   - name: acme~research
>     version: ^1.0.0
> builtins:
>   - name: ui
>     tools: [ui_prompt]
>   - name: console           # not available to Native agents
>   - name: guild             # not available to Native agents
> ```
>
> `environment` is Goose-only; declaring it on any other type is a build error. Providers: `anthropic`, `openai`, `gemini`, `meta`, `deepseek`, `alibaba`, `moonshot`, `zai`.
>
> Source: https://docs.guild.ai/guide/guild-yaml.md
>
> ## TypeScript SDK shape
>
> ```ts
> "use agent";
> import { agent, consoleTools, pick, userInterfaceTools, type Task } from "@guildai/agents-sdk";
> import { z } from "zod";
> import { summarize } from "./logic.ts";
>
> const description = "Summarizes open issues for a repository. Does not post anywhere.";
> const inputSchema = z.object({ type: z.literal("text").optional(), text: z.string().max(8_000) });
> const outputSchema = z.object({ summary: z.string() });
>
> const tools = { ...pick(userInterfaceTools, ["ui_prompt"]), ...consoleTools };
> type Tools = typeof tools;
>
> async function run(input: z.infer<typeof inputSchema>, task: Task<Tools>): Promise<z.infer<typeof outputSchema>> {
>   const result = await task.llm.generateText({ system: "Summarize briefly.", prompt: input.text });
>   return { summary: summarize(result.text) };
> }
>
> export default agent({ description, inputSchema, outputSchema, tools, run });
> ```
>
> Building blocks:
>
> - `llmAgent({ description, tools, systemPrompt, mode })`: prompt-driven agent; `mode` is `"one-shot"` (default) or `"multi-turn"`.
> - `agent({ description, inputSchema, outputSchema, tools, run })`: code-driven agent.
> - `pick(toolSet, ["tool_name"])`: register only the operations used.
> - `guildServiceTool(service, { description, inputSchema, outputSchema, endpoint, owner, versionNumber })`: one hand-declared integration operation (required for Slack).
> - `guildAgentTool({ calls: "owner~agent", inputSchema, outputSchema })`: call another Guild agent as a tool.
> - `task.tools.ui_prompt({ type: "text", text })`: pause for a human answer (needs `userInterfaceTools`).
> - `task.llm.generateText({ system, prompt })`: model call through Guild.
> - `task.gather([...])` / `task.gatherSettled([...])`: parallel calls, built inline.
> - Integration packages: `@guildai-services/<owner>~<integration>`, for example `@guildai-services/guildlabs~gmail-oauth`.
>
> `package.json` scripts follow `agents/expense-manager`: `build` (`tsc --build` + agent compiler + copy), `test` (`tsc --build && node --test logic.test.mjs`). `.npmrc` contains `@guildai:registry=https://app.guild.ai/npm/`.
>
> ## Credentials and policies
>
> - Scopes: account, workspace, member, or dedicated to one agent. A credential can be granted to one installed agent.
> - A credential proxy injects auth server-side; agents never see secret values. GitHub uses short-lived GitHub App tokens.
> - Credential policies are ALLOW/DENY rules by operation, resource, agent, and workspace; DENY wins; new credentials start allow-all.
>
> Sources: https://docs.guild.ai/platform/credentials.md, https://docs.guild.ai/platform/credential-policies.md
>
> ## Triggers
>
> - Event (for example a Slack mention or a GitHub pull request), schedule, and API.
> - `guild trigger create --frequency` accepts `HOURLY`, `DAILY`, `WEEKLY`, `MONTHLY`, and `CRON` (with `--cron-expression` and `--cron-timezone`, default UTC). A `CRON` schedule with a timezone, such as `Europe/Athens`, is converted to UTC.
>
> Source: https://docs.guild.ai/platform/triggers.md
>
> ## CLI cheat sheet
>
> ```bash
> guild auth login
> guild workspace list
> guild workspace select
>
> # create
> guild agent categories                                   # pick a category
> guild agent init --name <name> --agent-type <GUILD_NATIVE|GUILD_TYPESCRIPT|GOOSE|OPENCLAW|LANGGRAPH|ADK> \
>   --category <category> --owner <owner>
> guild agent init --name <name> --fork <owner~agent> --category <category> --owner <owner>
> guild agent init --name <name> --agent-type GUILD_TYPESCRIPT --template LLM \
>   --category <category> --owner <owner>                  # or AUTO_MANAGED_STATE, BLANK
>
> # integrations
> guild integration list
> guild integration operation list <owner~integration> --json
> guild integration create <name> --base-url <url> --auth-scheme api-key --header-template "Authorization: Bearer {token}"
> guild integration operation create <name> --openapi openapi.yaml
> guild integration connect <owner~integration>
>
> # test (guild agent test uploads only files git tracks)
> git add -A
> guild agent test
> guild agent test --mode json --timeout 300
> guild agent chat '<text or json>'
>
> # ship (only when asked)
> guild agent save --message "<summary>" --wait
> guild agent save --message "<summary>" --wait --publish   # first save after init: add --force
> guild api-key create --owner <owner> --name "Publish" --scopes agents:write   # for the Publish Agent to Guild Action
> guild workspace agent add <owner~agent> --workspace <owner~workspace>
> guild workspace chat --agent <owner~agent> --workspace <owner~workspace> --once "<request>"
>
> # triggers (only when asked)
> guild trigger create --workspace <owner~workspace> --type time --agent <owner~agent> \
>   --frequency WEEKLY --time 08:00 --days-of-week MONDAY --input '{"type":"text","text":"Weekly run"}'
> guild trigger create --workspace <owner~workspace> --type webhook --agent <owner~agent> \
>   --integration slack --event app_mention --input '{"type":"text","text":"{webhook_payload}"}'
> guild trigger create --workspace <owner~workspace> --type api --agent <owner~agent>
> guild trigger list
> ```
>
> CLI 0.28.0 `guild agent init --help` lists `GUILD_NATIVE`, `GUILD_TYPESCRIPT`, `GOOSE`, `OPENCLAW`, `LANGGRAPH`, and `ADK`. CLI 0.27.2 lists only `GUILD_TYPESCRIPT`, `GOOSE`, and `OPENCLAW`, and with `--template` it silently creates a TypeScript agent even when `OPENCLAW` is requested. Use CLI 0.28.0 or later (`npx @guildai/cli@latest agent init …`) and check `agent_type` in the generated `guild.json` before porting.
> ````

## Publish the migrated agent

The skill stops before publishing. Once you've reviewed the port and `guild agent test` passes, commit it to your repository and [publish it from GitHub Actions](https://docs.guild.ai/migrations/overview.md#publish-from-github-actions) with an account API key (`guild api-key create --scopes agents:write`), or run `guild agent save --wait --publish` yourself. The first save after `guild agent init` fails with "No saved state… use --force" because of the scaffold's `.gitignore`; add `--force` for now.

## Related pages

> [card] [Migrate to Guild](https://docs.guild.ai/migrations/overview.md)
>
> The method the skill follows, and the guide for each platform.

> [card] [Agent types](https://docs.guild.ai/guide/agent-types.md)
>
> Native, TypeScript, Goose, OpenClaw, and LangGraph.
