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
9 changes: 9 additions & 0 deletions engine/app/views/coplan/welcome/_default_agents.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<section class="landing__agents">
<h2 class="landing__section-title">Built for any AI agent</h2>
<p>
CoPlan exposes a self-describing REST API at
<%= link_to "/agent-instructions", agent_instructions_path, class: "landing__inline-link" %>.
Point any AI agent — Amp, Claude Code, Cursor, your own — at it and it can create plans,
apply edits, and leave review comments on your behalf.
</p>
</section>
16 changes: 7 additions & 9 deletions engine/app/views/coplan/welcome/_default_landing.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,13 @@
</div>
</section>

<section class="landing__agents">
<h2 class="landing__section-title">Built for any AI agent</h2>
<p>
CoPlan exposes a self-describing REST API at
<%= link_to "/agent-instructions", agent_instructions_path, class: "landing__inline-link" %>.
Point any AI agent — Amp, Claude Code, Cursor, your own — at it and it can create plans,
apply edits, and leave review comments on your behalf.
</p>
</section>
<%# The agents section is the one piece of the landing page hosts most often
need to customize — generic CoPlan points at /agent-instructions, while
a deployment like coplan-square wants to tell its users to run
`sq agents skills add coplan` instead. Renders via configuration so a
host can swap this single section without forking the whole landing
page. See `CoPlan.configuration.landing_agents_partial`. %>
<%= render CoPlan.configuration.landing_agents_partial %>

<% if signed_in? %>
<footer class="landing__footer">
Expand Down
14 changes: 14 additions & 0 deletions engine/lib/coplan/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@ class Configuration
# The engine ships a generic default at "coplan/welcome/default_landing".
attr_accessor :landing_page_partial

# Partial used to render the "Built for any AI agent" section of the
# landing page. This is the single piece of the landing page that hosts
# most often need to customize: the generic engine partial points users
# at `/agent-instructions`, while a deployment like coplan-square wants
# to tell its users to run `sq agents skills add coplan` instead.
#
# Swapping just this partial (rather than the whole landing page) lets
# hosts customize the agents callout without duplicating the hero, the
# how-it-works steps, or the CSS.
#
# The engine ships a generic default at "coplan/welcome/default_agents".
attr_accessor :landing_agents_partial

# VAPID (Voluntary Application Server Identification) keys for Web Push.
# Generate once with `bundle exec rails coplan:web_push:generate_keys`.
# Public key is shared with the browser; private key signs push messages.
Expand Down Expand Up @@ -49,6 +62,7 @@ def initialize
@agent_curl_prefix = 'curl -s -H "Authorization: Bearer $TOKEN"'
@seed_plan_types = []
@landing_page_partial = "coplan/welcome/default_landing"
@landing_agents_partial = "coplan/welcome/default_agents"
@agent_auth_instructions = <<~MARKDOWN
## Authentication

Expand Down
46 changes: 46 additions & 0 deletions spec/requests/welcome_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,50 @@
expect(response.body).not_to include("Design docs, built for AI-assisted planning")
end
end

describe "landing_agents_partial configuration override" do
# The agents section is the one piece of the landing page we expect hosts
# to most often swap out (generic /agent-instructions vs deployment-
# specific install commands like `sq agents skills add coplan`). Verify
# the swap happens *and* that the rest of the landing page is untouched.

before { sign_in_as(bob) }

context "with the default partial" do
it "renders the generic agents section pointing at /agent-instructions" do
get welcome_path
expect(response.body).to include("Built for any AI agent")
expect(response.body).to include("/agent-instructions")
end
end

context "with a host-configured override" do
around do |ex|
original = CoPlan.configuration.landing_agents_partial
CoPlan.configuration.landing_agents_partial = "coplan/welcome/test_agents_override"
ex.run
CoPlan.configuration.landing_agents_partial = original
end

before do
view_path = CoPlan::Engine.root.join("app/views/coplan/welcome/_test_agents_override.html.erb")
File.write(view_path, "<section class=\"host-agents\">sq agents skills add coplan</section>\n")
@tmp_view = view_path
end

after { File.delete(@tmp_view) if @tmp_view&.exist? }

it "swaps the agents section while keeping the rest of the landing page" do
get welcome_path

# The host's agents copy is rendered…
expect(response.body).to include("sq agents skills add coplan")
# …the default agents copy is gone…
expect(response.body).not_to include("Built for any AI agent")
# …but the hero and how-it-works steps are still the engine defaults.
expect(response.body).to include("Design docs, built for AI-assisted planning")
expect(response.body).to include("How it works")
end
end
end
end