<!--
Sitemap:
- [Installation](/installation)
- [Upgrading](/upgrading): Version-specific steps for upgrading an existing Bento install.
- [Concepts](/concepts)
- [Build your first pipeline](/tutorials/pipeline-args)
- [Target a specific issue or PR from a URL](/tutorials/url-targeting)
- [Keep state across runs](/tutorials/pipeline-state)
- [Fire a pipeline on a schedule or on demand](/tutorials/schedule-and-fire)
- [Configuration](/configuration)
- [Knowledge Base](/knowledge-base/)
- [Method & delivery](/knowledge-base/modes)
- [Config](/knowledge-base/config)
- [MCP](/knowledge-base/mcp)
- [Pipeline configuration reference](/pipelines/config)
- [Filters](/pipelines/filters)
- [Triggers](/triggers/)
- [GitHub Trigger](/triggers/github)
- [Linear Trigger](/triggers/linear)
- [Webhook](/triggers/webhook)
- [Schedule Trigger](/triggers/schedule)
- [Manual Trigger](/triggers/manual)
- [Traces](/pipelines/traces)
- [Slack](/integrations/slack)
- [Public Access](/public-access)
- [Context Engineering](/context-engineering)
- [Best Practices](/best-practices)
- [Troubleshooting](/troubleshooting)
- [Architecture](/architecture/vision)
- [Workspaces](/workspaces)
- [Authentication](/authentication)
- [Identity](/identity)
- [Security](/security)
- [References](/references)
- [Changelog](/changelog): Bento release history.
- [CLI Reference](/cli/)
- [Setup](/cli/setup)
- [Lifecycle](/cli/lifecycle)
- [Sandbox Image](/cli/image)
- [Observability](/cli/observability)
- [Diagnostics](/cli/diagnostics)
- [Triggers](/cli/triggers)
- [Workbench](/cli/workbench)
- [Auth](/cli/auth)
- [Knowledge](/cli/knowledge)
- [Bento](/index)
- [Runtime Wrapper](/architecture/runtime-wrapper)
- [Skill Evolve](/architecture/skill-evolve)
-->

# Manual Trigger

Every configured pipeline is fireable on demand. There is no key to opt in:

```bash
bento trigger fire <pipeline-name>
```

A pipeline with an event trigger is fireable too — firing it by hand and letting
an event fire it are the same dispatch:

```yaml
trigger:
  github:
    - pull_request.opened
agent: reviewer
```

A pipeline that only ever runs on demand declares no `trigger` at all.

A fire persists a trigger of kind `manual`, whatever the pipeline declares.

## Example: smoke test on demand

`trigger` here carries only the repo to check out — nothing fires this pipeline
automatically:

```yaml
name: smoke-tests
trigger:
  repo: acme/my-project
agent: solver
instructions: |
  Run the smoke tests and report pass/fail.
sandbox:
  backend: docker
```

```bash
bento trigger fire smoke-tests
```

## Typed inputs

A pipeline declares the inputs it accepts under `args:`. Each input has a
`type` (`string`, `number`, or `boolean`), an optional `required` flag, and an
optional `default`:

```yaml
name: summon-agent
trigger:
  repo: acme/my-project
agent: editor
args:
  persona:
    type: string
    required: true
  tone:
    type: string
    default: terse
instructions: |
  Draft a new agent persona ({{args.tone}} voice):

  {{args.persona}}
```

Pass inputs with repeatable `--arg key=value` flags:

```bash
bento trigger fire summon-agent --arg persona="a meticulous security auditor"
```

Validated values substitute into `instructions` as `{{args.<name>}}`, a namespace
distinct from the `{{event.*}}` webhook payload. Validation is strict: an
undeclared key, a missing required input, or a wrong type is rejected, and a
declared `default` fills an omitted input. A pipeline with no `args:` accepts no
inputs. Targeting flags (`--branch`/`--sha`/`--pr`) are separate from `args` and
never collide with a declared input.

An input can also be mapped off the trigger with `from:`, a template rendered
against `{{event.*}}` (the parsed payload) or `{{url.*}}` (`host`, `pathname`,
`segments.N`, `query.X`). This is how a pasted URL targets a specific item with
no daemon-side code — see [URL routing](#url-routing) below:

```yaml
args:
  issue:
    type: string
    default: ""                      # blank → the pipeline self-selects
    from: "{{event.issue.number}}"   # a pasted issue URL fills this
```

An explicit `--arg` overrides `from:`; an empty render falls back to `default`.

## URL routing

A pipeline can also be fired by pasting a URL — no pipeline name, no flags. Add
`trigger.patterns`, a list of URL prefixes that route to the pipeline:

```yaml
name: pr-review
trigger:
  github:
    - pull_request.opened
  patterns:
    - https://github.com/acme/backend/pull
    - https://github.com/acme/frontend/pull
agent: reviewer
```

```bash
bento trigger fire https://github.com/acme/backend/pull/42
```

The URL prefix-matches every pipeline's `patterns` to select the pipeline, then
is parsed into the same event a real webhook produces — so one pipeline serves
every repo in its `patterns` list. GitHub **pull request** (`/pull/<n>`) and
**issue** (`/issues/<n>`) URLs are both supported; the parser builds the event
the path describes — a PR URL's head ref and SHA are filled by a `gh` lookup, an
issue resolves to the repo's default branch.

Write `patterns` at the path granularity you want to route. A repo-level prefix
(`https://github.com/acme/backend`) matches both PR and issue URLs — fine when
one pipeline owns the repo, but if a PR-shaped and an issue-shaped pipeline share
a repo, give them `…/pull` and `…/issues` patterns so each shape routes to the
right pipeline (otherwise a URL matches both — the ambiguous error below).

`patterns` selects the pipeline; the URL's host selects the parser. Both extend
independently.

A URL matching no pipeline's `patterns` is an error; a URL matching more than
one is an error that lists them, not a fan-out across all of them.

To act on the *specific* item a URL names, map its identifier into an arg with
`from:`. The url surface exposes both the parsed payload (`{{event.*}}`) and the
raw URL parts (`{{url.host}}`, `{{url.pathname}}`, `{{url.segments.N}}`,
`{{url.query.X}}`), so a pipeline can target off any URL shape:

```yaml
trigger:
  patterns:
    - https://github.com/acme/backend/issues
args:
  issue:
    type: string
    default: ""                      # blank (schedule/manual) → self-select
    from: "{{event.issue.number}}"   # pasted issue URL → that issue
instructions: |
  Target issue: {{args.issue}}
  If a target is given, solve exactly that issue; otherwise pick one yourself.
```

```bash
bento trigger fire https://github.com/acme/backend/issues/42   # solves #42
```
