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
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ class AgentInstructionsController < ApplicationController
def show
@auth_instructions = CoPlan.configuration.agent_auth_instructions
@curl = CoPlan.configuration.agent_curl_prefix
@base = request.base_url
# Includes the engine's mount point — host apps may mount CoPlan under
# a prefix (e.g. /coplan), and request.base_url alone would point every
# curl example at the wrong path. root_path here is the engine's, which
# carries the request's SCRIPT_NAME.
@base = "#{request.base_url}#{root_path.chomp("/")}"
@plan_types = PlanType.order(:name)
render layout: false, content_type: "text/markdown", formats: [:text]
end
Expand Down
13 changes: 13 additions & 0 deletions engine/app/views/coplan/agent_instructions/show.text.erb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@ Interact with the CoPlan app to create, read, edit, and comment on plan document

<%= @auth_instructions %>

## Quick Start: The Editing Loop

Keeping a local Markdown file and syncing whole documents is the intended workflow — you do not need to express edits as granular operations. The canonical loop:

1. **Read** — `GET <%= @base %>/api/v1/plans/$PLAN_ID/snapshot`. Save `current_content` to a local file and note `current_revision`.
2. **Edit** the local file however you like.
3. **Write** — `PUT <%= @base %>/api/v1/plans/$PLAN_ID/content` with the full new content, `base_revision` set to the revision you read, and a specific `change_summary` (it becomes the version's label in the plan history — "Tightened rollout plan per Sam's feedback", not "Update").
4. **On `409 Conflict`** someone edited in between: re-read the snapshot, re-apply your changes to the fresh content, and PUT again with the new revision. Never retry with the stale `base_revision`.

The server diffs your content against the current revision, records granular operations automatically, and preserves comment anchors in unchanged regions. Re-read before every editing session — don't trust a local copy that's more than a few minutes old, and don't keep long-lived local state between tasks.

See [Editing Plans](#editing-plans-recommended-full-content-replacement) for the full request/response reference, and the lease + operations path only when you need a surgical single-operation edit.

## API Reference

### List Plans
Expand Down
2 changes: 2 additions & 0 deletions engine/app/views/coplan/llms/show.text.erb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

CoPlan has a REST API that AI agents can use to create plans, apply edits, and leave review comments.

The editing model is simple: read a plan's content and revision, edit the Markdown locally, and PUT the whole document back with `base_revision` for optimistic concurrency. The server diffs, versions, and preserves comment anchors automatically — no operation-by-operation editing required.

## API

- [Agent Instructions](<%= coplan.agent_instructions_path %>): Full API reference for AI agents, including authentication, endpoints, editing workflow, and commenting.
14 changes: 14 additions & 0 deletions spec/requests/agent_instructions_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,19 @@
get agent_instructions_path
expect(response.body).to include('"plan_type"')
end

it "builds example URLs from the request base (root mount)" do
get agent_instructions_path
expect(response.body).to include("http://www.example.com/api/v1/plans")
expect(response.body).not_to include("example.com//api")
end

it "includes the engine mount prefix in example URLs" do
# Host apps may mount the engine under a prefix (HOST_APP_GUIDE
# documents mount at "/coplan"); examples must include it or agents
# 404 on their first read.
get agent_instructions_path, env: { "SCRIPT_NAME" => "/coplan" }
expect(response.body).to include("http://www.example.com/coplan/api/v1/plans")
end
end
end
Loading