Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ telemetry into one STATUS_SPEC v1.0 HTTP surface per configured printer.

Monitoring is the default. A human approved (2026-10-04) a narrow,
human-in-the-loop control plane, enabled per deployment by `dispatch.enabled`:
STATUS_SPEC v1.1 claims plus exactly four verbs -- camera snapshot, chamber
STATUS_SPEC v1.1 claims plus exactly four verbs (and, since 2026-11-05, a
fifth on the A1 only; see below) -- camera snapshot, chamber
light (added 2026-10-05), `start_print` for an approved job after a person
confirms the plate is empty, and `stop_print`. On 2026-10-20 a human approved
the external spool (`vt_tray`) as a `start_print` mapping target for printers
Expand Down
4 changes: 3 additions & 1 deletion AGENT_RULES.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ the Bambu printer gateway.
decide the plate is empty from a camera snapshot it took under its claim
(`plate_check_method: agent_camera`, frame at most
`dispatch.agent_snapshot_max_age_s` old, deciding agent and rationale
recorded, frame archived with its SHA-256). The switch is off by default,
recorded, frame archived with its SHA-256). Under the same switch, approved
2026-11-05, it may also move the bed with `position_bed` as rule 1 allows
(`AGENTIC_LAB_DESIGN.md` §1.3, *Bambu A1 bed positioning*). The switch is off by default,
only an admin can flip it, and every flip is audited. Nothing else changes:
on every other printer, and on the A1 with the switch off, the rule above
holds in full, and no agent ever retries a failed or uncertain dispatch.
Expand Down
37 changes: 24 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ confirms the plate is empty before every start, except on a printer whose
**agent mode** an admin has switched on — approved 2026-11-02 for the Bambu A1
(`bambu_a1_01`) only — where an agent may decide from a claimed camera
snapshot ([Agent mode](#agent-mode-bambu-a1-only)). The third-party library's
other command methods remain unreachable. Control is not yet exposed as
`lab-skills` skills.
other command methods remain unreachable. Control is not yet exposed as merged
`lab-skills` skills (ac-organic-lab PR #98 adds the A1's); until then the lab
rules let agents use the A1 agent-mode workflow on this API directly.

Every job keeps a durable, schema-versioned **result bundle** and its exact
artifact on the gateway's disk. Filing a record in the ELN is optional and goes
Expand Down Expand Up @@ -182,7 +183,8 @@ sliced) plate is reported.
**Events.** `GET /events?after=<event_id>` (or the webhooks in
`agent_workflow.event_webhook_urls`) delivers `job.started`, one event per
terminal state (`job.finished`, `job.failed`, `job.rejected`,
`job.cancelled`), `job.cooled`, and `gateway.restarted`. Each event carries
`job.cancelled`), `job.cooled`, `bed.moved` (A1 `position_bed`), and
`gateway.restarted`. Each event carries
`schema_version`, `event_id`, `gateway_id`, `boot_id`, `submission_id`,
`printer_id`, `state`, `updated_at`, `eln_project` and `note`. Event ids are
zero-padded decimals that keep increasing across restarts (they are kept in
Expand All @@ -201,18 +203,26 @@ logged and never affect a job.

**End-to-end for an agent:**

1. `POST /submissions` (sliced `.3mf`, `target_machine`, optional `eln_project`).
1. `POST /submissions` (sliced `.3mf`, or an `.stl` with `material` and
optionally `placement=front_left`; `target_machine`; optional `eln_project`).
2. Approval: a person approves — or, on the A1 in agent mode, the agent.
3. `POST /printers/{id}/control/claim`, then keep it alive with `heartbeat`.
4. Plate check: a person confirms (`in_person` / `printer_camera`) — or, in
4. On the A1, `POST /printers/bambu_a1_01/control/position_bed`
`{"position": "inspect", "bed_path_clear": true}` once the arm is confirmed
clear, because the last print left the bed parked forward out of the
camera's view.
5. Plate check: a person confirms (`in_person` / `printer_camera`) — or, in
agent mode, the agent takes `POST /printers/{id}/control/snapshot`, judges
the returned `image_base64` itself, and keeps the `token`.
5. `POST /printers/{id}/control/start_print` (see [Agent mode](#agent-mode-bambu-a1-only)).
6. Wait for `job.finished` (or `job.failed`) on `/events` or a webhook.
7. Wait for cool-down: `job.cooled`, or poll
6. `POST /printers/{id}/control/start_print` (see [Agent mode](#agent-mode-bambu-a1-only)),
then release the claim.
7. Wait for `job.finished` (or `job.failed`) on `/events` or a webhook. The
A1's end gcode parks the bed at `end_bed_y_mm` (Y 250 here) for pickup.
8. Wait for cool-down: `job.cooled`, or poll
`GET /submissions/{id}/pickup-targets` until `ready`.
8. Hand the bed-frame `objects` to the arm agent, which applies its own
calibration. The bundle at `/submissions/{id}/result` keeps the record.
9. Hand the bed-frame `objects` and `bed_park_y_mm` to the arm agent, which
applies its own calibration. The bundle at `/submissions/{id}/result` keeps
the record.

`agent_workflow.vision_enabled` adds an optional, dependency-light advisory
check, `POST /printers/{id}/bed-check`, that compares a claimed snapshot with an
Expand All @@ -224,7 +234,8 @@ decision.
### Agent mode (Bambu A1 only)

Approved by Yang on 2026-11-02. With the switch on, an agent may submit,
approve and start jobs on the Bambu A1, deciding itself that the plate is empty.
approve and start jobs on the Bambu A1, deciding itself that the plate is empty,
and (approved 2026-11-05) move its bed with `position_bed`.
Everywhere else, and on the A1 with the switch off, agents are refused and the
human-in-the-loop path is unchanged.

Expand All @@ -245,8 +256,8 @@ human-in-the-loop path is unchanged.
verified identity and the agent id are both recorded
(`requested_by_agent`, `approved_by_agent`, `dispatch.dispatched_by_agent`).
- **Refusals** are 403 with `agent_mode: "not_eligible"` (any printer but the
A1) or `agent_mode: "off"` (switch off), for agent submissions, approvals and
starts.
A1) or `agent_mode: "off"` (switch off), for agent submissions, approvals,
bed moves and starts.

An agent's start, on the A1 with the switch on:

Expand Down
32 changes: 26 additions & 6 deletions docs/API_REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,13 @@ the routes enabled in a deployment.
| Optional vision advisory | `POST /printers/{id}/bed-check` (dispatch and vision enabled) |
| Documentation | `GET /docs`, `/openapi.json`, `/agent-docs`, `/agent-docs/api-reference`, `/docs/agent`, `/llms.txt` |

Agents use the SDK for printer I/O. An occupied or unclear claimed snapshot
means release the claim and stop; never send a start request to test the gate.
Failed or uncertain dispatches require human reconciliation, without retries.
Until `lab-skills` merges its Bambu skills (ac-organic-lab PR #98), the lab
rules (`AGENTIC_LAB_DESIGN.md` §1.3) let an agent drive only the A1 agent-mode
workflow, `position_bed` included, directly on this API through the
authenticated edge; see the [agent guide](../src/bambu_server/docs/AGENT_GUIDE.md).
An occupied or unclear claimed snapshot means release the claim and stop;
never send a start request to test the gate. Failed or uncertain dispatches
and undelivered bed moves require human reconciliation, without retries.

## Printer inventory

Expand Down Expand Up @@ -115,6 +119,20 @@ failed gate; `allowed_actions` on `/status` mirrors them, and
the camera frame a start was confirmed against. Without dispatch enabled the
control routes are absent; the stored plate-evidence route remains registered.

**Bed positioning (Bambu A1 only).** `POST /printers/bambu_a1_01/control/position_bed`
with the claim token and `{"position": "inspect" | "pickup", "bed_path_clear": true,
"reason"?: "..."}` moves the bed along Y only to the configured position
(`bed_positions` on the printer: `inspect_y_mm`, where the camera sees the
whole plate, and `pickup_y_mm`, kept equal to the slicer's `end_bed_y_mm`).
It returns `{printer_id, position, y_mm, requested_at, moved_by,
moved_by_verified, agent_id, note}`. Refusals: 423 without the claim; 412 when
the printer is not idle, reports an error, has a gateway job in flight, or has
no `bed_positions` (every printer but the A1); 403 for an unverified caller, or
an agent while agent mode is off; 422 when `bed_path_clear` is not `true` or
the position is unknown; 502 when the command was not delivered (never retry).
The printer does not report bed position, so confirm with a snapshot. A
delivered move emits `bed.moved`.

**Camera snapshot for a plate check.** `POST /printers/{id}/control/snapshot`
with the claim token returns `{token, printer_id, captured_at, sha256,
content_type: "image/jpeg", image_base64}`. The token is valid for that printer
Expand All @@ -132,7 +150,8 @@ authenticated surface. Never send secrets or printer addresses in submissions.

Approved 2026-11-02 for `bambu_a1_01`. An agent is a request carrying
`X-Agent-Id`, or whose edge-verified role is in `dispatch.agent_roles`
(default `agent`). Agents may submit, approve and start only on a printer with
(default `agent`). Agents may submit, approve, move the bed (`position_bed`)
and start only on a printer with
`agent_mode_eligible: true` (config accepts it on a Bambu A1 only) whose switch
is on; otherwise 403 with `agent_mode: "not_eligible"` or `"off"`.

Expand Down Expand Up @@ -195,8 +214,9 @@ parking at Y 250 instead of the stock Y 180 puts every object 70 mm further
toward the front of the printer.

`GET /events?after=<event_id>` is a pollable lifecycle feed: `job.started`,
`job.finished`, `job.failed`, `job.rejected`, `job.cancelled`, `job.cooled`
and `gateway.restarted`, each with `schema_version`, `event_id`,
`job.finished`, `job.failed`, `job.rejected`, `job.cancelled`, `job.cooled`,
`bed.moved` (printer id and a note naming the position, Y, who and why) and
`gateway.restarted`, each with `schema_version`, `event_id`,
`gateway_id`, `boot_id`, `submission_id`, `printer_id`, `state`,
`updated_at`, `eln_project`, `note`, and for job events the bed-frame
`object_positions`; `job.finished` and `job.cooled` add `pickup`. Ids persist
Expand Down
Loading
Loading