agnes-the-ai-analyst/app/web/templates/home_not_onboarded.html
Vojtech a46b9dc928
/home install-hero polish: license link contrast, auto-mode reorder, Shift+Tab guidance (#243)
* Make /home install-hero links readable against blue background

The Claude license-options link added in the previous commit inherited
the default `<a>` style (`var(--hp-primary)` blue), which renders as
blue-on-blue and is unreadable inside the blue install-hero. Add a
scoped `.install-hero a` rule that uses white with an underline
(matching the existing lead-paragraph contrast pattern) so any link
nested in the hero stays legible.

* Reorder /home install flow: auto-mode is now Step 2, Agnes install becomes Step 3

Step 3 (was Step 2) pastes a ~20-command bash bootstrap into a fresh
Claude Code session. Without auto-mode enabled first, each Bash/edit
command needs a manual approve click — bad UX for first-time users.

Move auto-mode from the outside-hero `<details>` reference block into
the install-hero as a real Step 2, between "install Claude Code" and
"install Agnes". Content is the persistent `acceptEdits` snippet
(write to ~/.claude/settings.json) plus a one-liner pointing at
Shift+Tab for users who are already inside a running Claude Code
session. YOLO mode for full Bash auto-approve stays on
/setup-advanced behind the existing link.

The outside-hero `setup-collapsible[data-section="step3"]` block is
dropped — auto-mode is no longer reference content, it's a real
install step, and duplicating it would just diverge over time.
Onboarded users no longer see the auto-mode block at all (consistent
with Steps 1 + 3 also hiding post-onboarding).

Completion banner copy updated: "Step 1, 2 & 3 done — Claude Code
installed, auto-mode set, Agnes ready". Dashboard CTA partial and
other templates don't reference step numbers for this flow, so no
adaptation needed there.

* Simplify /home Step 2 to Shift+Tab only — drop the JSON snippet

Operator pointed out two issues with the prior Step 2:

1. The settings.json snippet is redundant. Claude Code's first
   Shift+Tab cycle to auto-accept mode already prompts the user
   whether to persist it as default — Claude writes the config
   itself, no manual file edit needed.

2. The snippet only showed the POSIX path `~/.claude/settings.json`,
   which doesn't translate to native Windows.

Replace the snippet + copy button with a plain Shift+Tab instruction,
explicitly call out the first-time "make this the default?" prompt,
and note that Claude handles the config write itself — same flow on
macOS / Linux / WSL / Windows. Adds a fallback line for users who
already closed the post-OAuth session.

* Tighten /home Step 2 install-note to two paragraphs

Operator: drop the 'Claude writes the setting itself, so this works
the same on macOS / Linux / WSL / Windows...' line plus the
'auto-approves file edits going forward; Bash commands stay gated
— that's the safe default' line. Both were filler — the make-default
prompt already implies persistence, and gated Bash is the obvious
default users won't be surprised by.

Result: paragraph 1 carries Shift+Tab + first-time make-default
say-yes + closed-session fallback in one breath; paragraph 2 keeps
the verbatim YOLO link. Same affordances, less vertical space.
2026-05-11 16:46:58 +00:00

1691 lines
62 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends "base.html" %}
{% block title %}Setup — {{ instance_name or "AI Data Analyst" }}{% endblock %}
{% block content %}
{% include "_page_chrome.html" %}
<style>
.home-mock {
--hp-primary: #0073D1;
--hp-primary-dark: #0056A3;
--hp-primary-light: #E6F3FC;
--hp-border: #E5E7EB;
--hp-border-light: #F3F4F6;
--hp-text-primary: #111827;
--hp-text-secondary: #6B7280;
--hp-text-muted: #9CA3AF;
--hp-orange: #C2410C;
--hp-orange-light: #FED7AA;
--hp-font-mono: ui-monospace, "SF Mono", Consolas, monospace;
color: var(--hp-text-primary);
font-size: 14px;
line-height: 1.5;
}
.home-mock * { box-sizing: border-box; }
.home-mock .install-hero {
background: linear-gradient(135deg, #0073D1 0%, #0056A3 100%);
color: white;
border-radius: 16px;
padding: 38px 40px;
margin-bottom: 22px;
box-shadow: 0 8px 24px rgba(0, 86, 163, 0.18);
}
.home-mock .install-hero .eyebrow {
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.8px;
opacity: 0.85;
margin-bottom: 10px;
}
.home-mock .install-hero h1 {
font-size: 30px;
font-weight: 600;
letter-spacing: -0.4px;
margin-bottom: 12px;
line-height: 1.2;
color: white;
}
.home-mock .install-hero .lead {
font-size: 15px;
opacity: 0.94;
line-height: 1.6;
margin-bottom: 22px;
}
.home-mock .install-hero .lead strong { font-weight: 600; }
.home-mock .what-is {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 14px;
margin-bottom: 18px;
}
.home-mock .what-is-item {
background: white;
border: 1px solid var(--hp-border);
border-radius: 12px;
padding: 18px 22px;
color: inherit;
text-decoration: none;
display: block;
transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}
.home-mock a.what-is-item:hover {
border-color: var(--hp-primary);
box-shadow: 0 4px 12px rgba(0, 115, 209, 0.10);
transform: translateY(-1px);
}
.home-mock .what-is-item .ico { font-size: 22px; margin-bottom: 8px; display: block; }
.home-mock .what-is-item .ttl {
font-size: 14px;
font-weight: 600;
color: var(--hp-text-primary);
margin-bottom: 4px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.home-mock .what-is-item .ttl .arrow {
color: var(--hp-primary);
font-weight: 600;
transition: transform 0.15s ease;
}
.home-mock a.what-is-item:hover .ttl .arrow {
transform: translateX(2px);
}
.home-mock .what-is-item .desc {
font-size: 13px;
color: var(--hp-text-secondary);
line-height: 1.55;
}
.home-mock .look-around-lead {
font-size: 13px;
color: var(--hp-text-secondary);
line-height: 1.55;
margin: -4px 0 12px;
}
.home-mock .look-around-grid {
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
margin-bottom: 22px;
}
.home-mock .connector-tiles {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 16px;
margin-bottom: 26px;
}
.home-mock .connector-tile {
background: white;
border: 1px solid var(--hp-border);
border-radius: 12px;
padding: 20px 22px;
display: flex;
flex-direction: column;
}
.home-mock .connector-tile .ico {
font-size: 24px;
margin-bottom: 10px;
line-height: 1;
}
.home-mock .connector-tile .ttl {
font-size: 15px;
font-weight: 600;
color: var(--hp-text-primary);
margin-bottom: 6px;
}
.home-mock .connector-tile .desc {
font-size: 13px;
color: var(--hp-text-secondary);
line-height: 1.55;
margin-bottom: 14px;
flex: 1;
}
.home-mock .connector-tile .connector-actions {
display: flex;
flex-direction: column;
gap: 8px;
}
.home-mock .connector-tile .connector-copy {
align-self: flex-start;
}
.home-mock .install-block {
background: rgba(15, 23, 42, 0.55);
border: 1px solid rgba(255, 255, 255, 0.10);
border-radius: 12px;
padding: 18px 20px;
}
.home-mock .install-block + .install-block { margin-top: 14px; }
.home-mock .os-tabs {
display: flex;
gap: 4px;
margin-bottom: 8px;
border-bottom: 1px solid rgba(255, 255, 255, 0.10);
}
.home-mock .os-tab {
background: transparent;
border: none;
color: rgba(255, 255, 255, 0.60);
font-size: 12px;
font-weight: 500;
padding: 8px 14px;
cursor: pointer;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
font-family: inherit;
}
.home-mock .os-tab:hover { color: rgba(255, 255, 255, 0.85); }
.home-mock .os-tab.is-active {
color: white;
border-bottom-color: #FBBF24;
}
/* `[hidden]` UA stylesheet has lower specificity than `.install-cmd { display: flex }`,
so we need an explicit override to actually hide the inactive tab panel. */
.home-mock .install-cmd[hidden] { display: none; }
.home-mock .install-block .label {
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.6px;
opacity: 0.78;
margin-bottom: 10px;
font-weight: 600;
}
.home-mock .install-cmd {
background: #0F172A;
border: 1px solid rgba(255, 255, 255, 0.10);
border-radius: 8px;
padding: 14px 18px;
font-family: var(--hp-font-mono);
font-size: 13.5px;
color: #FBBF24;
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 16px;
}
.home-mock .install-cmd .multiline { display: block; line-height: 1.7; white-space: pre-wrap; flex: 1; }
.home-mock .install-cmd .copy-btn {
background: rgba(255, 255, 255, 0.10);
color: white;
border: 1px solid rgba(255, 255, 255, 0.18);
padding: 7px 14px;
border-radius: 6px;
font-size: 12px;
cursor: pointer;
font-weight: 500;
flex-shrink: 0;
}
.home-mock .install-cmd .copy-btn:hover { background: rgba(255, 255, 255, 0.18); }
.home-mock .install-note {
font-size: 12.5px;
color: rgba(255, 255, 255, 0.85);
margin-top: 12px;
line-height: 1.55;
}
.home-mock .install-note code,
.home-mock .install-note > code {
background: rgba(255, 255, 255, 0.12);
padding: 1px 6px;
border-radius: 4px;
font-family: var(--hp-font-mono);
font-size: 11.5px;
}
/* Links inside the blue install-hero need a non-blue color — the default
`<a>` style elsewhere on /home renders as `var(--hp-primary)` blue,
which is invisible against the hero's blue background. Use the same
high-contrast white-with-underline pattern the lead paragraph uses,
and bump hover to full white so the affordance stays obvious. */
.home-mock .install-hero a {
color: #ffffff;
text-decoration: underline;
text-decoration-color: rgba(255, 255, 255, 0.6);
text-underline-offset: 2px;
}
.home-mock .install-hero a:hover,
.home-mock .install-hero a:focus {
color: #ffffff;
text-decoration-color: #ffffff;
}
.home-mock .automode-card {
margin: 22px 0;
background: white;
border: 1px solid var(--hp-border);
border-radius: 12px;
padding: 18px 22px;
}
.home-mock .automode-head {
display: flex;
gap: 14px;
align-items: flex-start;
margin-bottom: 14px;
}
.home-mock .automode-head .ico {
font-size: 22px;
flex-shrink: 0;
line-height: 1;
}
.home-mock .automode-head h3 {
font-size: 14px;
font-weight: 600;
margin-bottom: 4px;
color: var(--hp-text-primary);
}
.home-mock .automode-head p {
font-size: 13px;
color: var(--hp-text-secondary);
line-height: 1.55;
margin: 0;
}
.home-mock .automode-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 14px;
}
.home-mock .automode-step {
display: flex;
gap: 10px;
align-items: flex-start;
padding: 12px;
background: var(--hp-border-light);
border-radius: 8px;
}
.home-mock .automode-step .num {
width: 22px; height: 22px;
border-radius: 50%;
background: var(--hp-primary-light);
color: var(--hp-primary);
flex-shrink: 0;
display: flex; align-items: center; justify-content: center;
font-weight: 700; font-size: 11px;
}
.home-mock .automode-step .step-text {
flex: 1;
font-size: 12.5px;
line-height: 1.5;
color: var(--hp-text-secondary);
}
.home-mock .automode-step .step-text strong {
display: block;
color: var(--hp-text-primary);
margin-bottom: 4px;
font-size: 13px;
}
.home-mock .automode-step kbd {
background: white;
border: 1px solid var(--hp-border);
border-bottom-width: 2px;
border-radius: 4px;
padding: 1px 6px;
font-size: 11px;
font-family: var(--hp-font-mono);
color: var(--hp-text-primary);
}
.home-mock .automode-step code {
font-family: var(--hp-font-mono);
font-size: 11.5px;
background: white;
padding: 1px 5px;
border-radius: 3px;
color: var(--hp-text-primary);
border: 1px solid var(--hp-border);
}
.home-mock .automode-code {
background: #0F172A;
color: #FBBF24;
border-radius: 6px;
padding: 8px 10px;
margin-top: 6px;
font-family: var(--hp-font-mono);
font-size: 11.5px;
line-height: 1.5;
overflow-x: auto;
white-space: pre;
}
.home-mock .automode-foot {
margin-top: 12px;
padding-top: 10px;
border-top: 1px solid var(--hp-border-light);
font-size: 12px;
color: var(--hp-text-secondary);
line-height: 1.5;
}
.home-mock .automode-foot a { color: var(--hp-primary); text-decoration: underline; }
.home-mock .automode-foot code {
font-family: var(--hp-font-mono);
font-size: 11px;
background: var(--hp-border-light);
padding: 1px 4px;
border-radius: 3px;
}
.home-mock .section-label {
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.6px;
color: var(--hp-text-secondary);
margin: 30px 0 12px;
}
.home-mock .grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 18px;
margin-bottom: 18px;
}
.home-mock .card {
background: white;
border: 1px solid var(--hp-border);
border-radius: 12px;
padding: 22px;
}
.home-mock .card h3 { font-size: 14px; font-weight: 600; margin-bottom: 6px; }
.home-mock .card p { font-size: 13px; color: var(--hp-text-secondary); line-height: 1.55; margin-bottom: 12px; }
.home-mock .card-list { list-style: none; padding: 0; margin: 0; }
.home-mock .card-list li {
display: flex;
align-items: flex-start;
gap: 10px;
padding: 8px 0;
font-size: 13px;
border-bottom: 1px solid var(--hp-border-light);
}
.home-mock .card-list li:last-child { border-bottom: none; }
.home-mock .card-list .num {
width: 22px; height: 22px;
border-radius: 50%;
background: var(--hp-primary-light);
color: var(--hp-primary);
flex-shrink: 0;
display: flex; align-items: center; justify-content: center;
font-weight: 700; font-size: 11px;
}
.home-mock .card-list .step-text { flex: 1; line-height: 1.55; }
.home-mock .card-list .step-text strong { display: block; margin-bottom: 2px; }
.home-mock .card-list .step-text code,
.home-mock .card-mini-cmd code {
font-family: var(--hp-font-mono);
font-size: 11.5px;
background: var(--hp-border-light);
padding: 1px 5px;
border-radius: 3px;
color: var(--hp-text-primary);
}
.home-mock .card-mini-cmd {
margin-top: 6px;
padding: 8px 10px;
background: #0F172A;
color: #FBBF24;
border-radius: 6px;
font-family: var(--hp-font-mono);
font-size: 11.5px;
line-height: 1.5;
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 8px;
}
.home-mock .card-mini-cmd code {
background: transparent;
color: inherit;
padding: 0;
flex: 1;
white-space: pre-wrap;
word-break: break-word;
}
.home-mock .connector-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.home-mock .connector-head strong {
display: inline;
margin-bottom: 0;
}
.home-mock .connector-copy {
background: var(--hp-primary);
color: white;
border: none;
border-radius: 6px;
padding: 5px 12px;
font-size: 12px;
font-weight: 600;
cursor: pointer;
font-family: inherit;
flex-shrink: 0;
}
.home-mock .connector-copy:hover { background: var(--hp-primary-dark); }
.home-mock .connector-copy.copied { background: #047857; }
.home-mock details.connector-preview {
margin-top: 6px;
}
.home-mock details.connector-preview > summary {
cursor: pointer;
list-style: none;
font-size: 11.5px;
color: var(--hp-text-secondary);
padding: 2px 0;
user-select: none;
}
.home-mock details.connector-preview > summary::-webkit-details-marker { display: none; }
.home-mock details.connector-preview > summary::before {
content: "▸ ";
margin-right: 2px;
}
.home-mock details.connector-preview[open] > summary::before { content: "▾ "; }
.home-mock details.connector-preview > summary:hover { color: var(--hp-text-primary); }
.home-mock details.connector-preview .card-mini-cmd { margin-top: 6px; }
.home-mock .explore-list { list-style: none; padding: 0; margin: 0; }
.home-mock .explore-list li + li { margin-top: 8px; }
.home-mock .explore-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 14px;
background: var(--hp-border-light);
border: 1px solid transparent;
border-radius: 8px;
text-decoration: none;
color: var(--hp-text-primary);
transition: border-color 0.15s ease, background 0.15s ease;
}
.home-mock .explore-item:hover {
border-color: var(--hp-primary);
background: var(--hp-primary-light);
}
.home-mock .explore-item .ico {
font-size: 22px;
flex-shrink: 0;
width: 28px;
text-align: center;
}
.home-mock .explore-item .explore-text {
flex: 1;
font-size: 13px;
color: var(--hp-text-secondary);
line-height: 1.45;
}
.home-mock .explore-item .explore-text strong {
display: block;
color: var(--hp-text-primary);
font-size: 13.5px;
font-weight: 600;
margin-bottom: 2px;
}
.home-mock .explore-item .arrow {
color: var(--hp-primary);
font-size: 16px;
flex-shrink: 0;
font-weight: 600;
}
.home-mock .advanced-pointer {
display: flex;
align-items: center;
gap: 14px;
margin-top: 10px;
padding: 16px 22px;
background: white;
border: 1px solid var(--hp-border);
border-left: 4px solid var(--hp-primary);
border-radius: 12px;
text-decoration: none;
color: inherit;
transition: background 0.15s ease, border-color 0.15s ease;
}
.home-mock .advanced-pointer:hover {
background: var(--hp-primary-light);
border-color: var(--hp-primary);
}
.home-mock .advanced-pointer .ico {
font-size: 22px;
flex-shrink: 0;
line-height: 1;
}
.home-mock .advanced-pointer-text {
flex: 1;
font-size: 13px;
color: var(--hp-text-secondary);
line-height: 1.55;
}
.home-mock .advanced-pointer-text strong {
display: block;
color: var(--hp-text-primary);
font-size: 14px;
font-weight: 600;
margin-bottom: 2px;
}
.home-mock .advanced-pointer .arrow {
color: var(--hp-primary);
font-size: 16px;
font-weight: 600;
flex-shrink: 0;
}
.home-mock .setup-cta-lead {
font-size: 13px;
color: rgba(255, 255, 255, 0.82);
margin-bottom: 14px;
line-height: 1.55;
}
.home-mock .setup-cta-lead code {
background: rgba(255, 255, 255, 0.12);
padding: 1px 6px;
border-radius: 4px;
font-family: var(--hp-font-mono);
font-size: 11.5px;
}
.home-mock .setup-cta-row {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 14px;
}
.home-mock .btn-setup-primary {
font-family: inherit;
font-size: 13px;
font-weight: 600;
color: var(--hp-primary);
background: #FFFFFF;
border: none;
border-radius: 6px;
padding: 10px 22px;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 8px;
white-space: nowrap;
transition: background 0.15s ease;
}
.home-mock .btn-setup-primary:hover { background: #F0F7FF; }
.home-mock .btn-setup-primary.copied { background: #047857; color: #fff; }
.home-mock .btn-setup-primary[disabled] { opacity: 0.7; cursor: wait; }
.home-mock .setup-cta-meta {
display: inline-flex;
align-items: center;
gap: 14px;
flex-wrap: wrap;
}
.home-mock .setup-cta-hint {
font-size: 12px;
color: rgba(255, 255, 255, 0.65);
}
.home-mock details.manual-fallback {
margin-top: 14px;
border-top: 1px solid rgba(255, 255, 255, 0.10);
padding-top: 12px;
}
.home-mock details.manual-fallback > summary {
cursor: pointer;
list-style: none;
font-size: 12.5px;
color: rgba(255, 255, 255, 0.78);
padding: 4px 0;
user-select: none;
}
.home-mock details.manual-fallback > summary::-webkit-details-marker { display: none; }
.home-mock details.manual-fallback > summary::before {
content: "▸ ";
display: inline-block;
transition: transform 0.15s ease;
margin-right: 4px;
}
.home-mock details.manual-fallback[open] > summary::before { content: "▾ "; }
.home-mock .manual-preview-wrap { margin-top: 10px; }
.home-mock .manual-preview-wrap .setup-preview-pre {
background: #0F172A;
color: #E2E8F0;
border: 1px solid rgba(255, 255, 255, 0.10);
border-radius: 8px;
padding: 14px 16px;
font-family: var(--hp-font-mono);
font-size: 12.5px;
line-height: 1.55;
overflow-x: auto;
white-space: pre-wrap;
word-break: break-word;
margin: 0;
}
/* Override the global `code { background: var(--bg); }` rule so the inner
<code> renders white-on-navy instead of dark-on-pale (unreadable). */
.home-mock .manual-preview-wrap .setup-preview-pre code,
.home-mock .manual-preview-wrap .setup-preview-code {
background: transparent;
color: #E2E8F0;
padding: 0;
border-radius: 0;
font-family: inherit;
font-size: inherit;
}
.home-mock .manual-preview-wrap .placeholder-token {
background: rgba(251, 191, 36, 0.20);
color: #FBBF24;
padding: 0 4px;
border-radius: 3px;
font-style: italic;
}
.home-mock .manual-preview-wrap .token-revealed {
background: rgba(16, 185, 129, 0.18);
color: #6EE7B7;
padding: 0 4px;
border-radius: 3px;
font-style: normal;
word-break: break-all;
}
/* In-hero (dark) variant: shown for not-onboarded users underneath the
inline install steps inside the blue hero. */
.home-mock .self-mark {
margin-top: 16px;
font-size: 13px;
color: rgba(255, 255, 255, 0.85);
}
.home-mock .self-mark button {
background: rgba(255, 255, 255, 0.15);
color: white;
border: 1px solid rgba(255, 255, 255, 0.30);
padding: 6px 12px;
border-radius: 6px;
font-size: 12px;
font-weight: 500;
cursor: pointer;
margin-left: 6px;
}
.home-mock .self-mark button:hover { background: rgba(255, 255, 255, 0.25); }
.home-mock .self-mark button:disabled { opacity: 0.5; cursor: default; }
.home-mock .self-mark .status { margin-left: 10px; font-style: italic; }
/* Onboarded "steps complete" badge — shown inside the blue hero in
place of the hidden Step 1 + Step 2 install-blocks. */
.home-mock .install-done {
margin-top: 4px;
margin-bottom: 4px;
padding: 12px 16px;
background: rgba(255, 255, 255, 0.10);
border: 1px solid rgba(255, 255, 255, 0.18);
border-radius: 10px;
color: rgba(255, 255, 255, 0.92);
font-size: 13px;
line-height: 1.55;
display: flex;
align-items: flex-start;
gap: 10px;
}
.home-mock .install-done .check {
font-size: 16px;
line-height: 1.3;
flex-shrink: 0;
}
.home-mock .install-done strong { font-weight: 600; color: white; }
/* News perex (admin-edited) — bottom of /home.
Keeps the styling within the admin-defined class vocabulary
(callout, video-embed) so authors get a predictable surface.
Full-width grid classes are intentionally NOT included here —
they live on /news where the layout has more room. */
.home-mock .home-news {
margin-top: 28px;
background: white;
border: 1px solid var(--hp-border);
border-radius: 12px;
overflow: hidden; /* keep the green strip's corners rounded */
}
.home-mock .home-news-head {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 16px;
padding: 12px 22px;
background: #D1FAE5; /* same green as .callout-success */
border-bottom: 1px solid #A7F3D0;
}
.home-mock .home-news-head h2 {
font-size: 14px;
font-weight: 600;
color: #047857; /* darker green for contrast on the band */
margin: 0;
text-transform: uppercase;
letter-spacing: 0.6px;
}
.home-mock .home-news-more {
font-size: 13px;
font-weight: 500;
color: #047857;
text-decoration: none;
}
.home-mock .home-news-more:hover { text-decoration: underline; }
.home-mock .home-news-body {
font-size: 14px;
line-height: 1.55;
color: var(--hp-text-primary);
padding: 18px 22px;
}
.home-mock .home-news-body p { margin: 0 0 8px; }
.home-mock .home-news-body p:last-child { margin-bottom: 0; }
/* Setup-collapsible: each post-install section (Step 3 auto-mode,
Connect-your-tools) is wrapped in a <details open> so it keyboard-
collapses without JS. Default state on /home: summary hidden, body
flat — visually identical to the pre-collapse layout.
When the user clicks "Minimize setup view" in the hero, JS sets
`data-setup-minimized="1"` on `.home-mock` and removes the `open`
attribute on each <details>. The summary then appears as a slim
gray bar; the body collapses; clicking the bar re-opens that one
section. localStorage persists the minimize state per device. */
.home-mock .setup-collapsible { margin-top: 22px; }
.home-mock .setup-collapsible > summary {
/* Default: summary is structural-only. The "flat" rendering is
handled by the inner blocks (.automode-card already provides its
own padding/border/background; the connect-your-tools section
starts with a .section-label-flat). */
display: none;
}
.home-mock .setup-collapsible > summary::-webkit-details-marker { display: none; }
/* Minimize ON: summary becomes a slim clickable bar; the inner body
inherits the existing block styling but tucks under the summary
when the <details> is closed. */
.home-mock[data-setup-minimized="1"] .setup-collapsible {
border: 1px solid var(--hp-border);
border-radius: 12px;
background: white;
overflow: hidden;
}
.home-mock[data-setup-minimized="1"] .setup-collapsible > summary {
list-style: none;
cursor: pointer;
padding: 14px 22px;
display: flex;
align-items: center;
gap: 12px;
font-size: 14px;
font-weight: 600;
color: var(--hp-text-primary);
background: #F9FAFB;
border-bottom: 1px solid transparent;
transition: background 120ms ease;
user-select: none;
}
.home-mock[data-setup-minimized="1"] .setup-collapsible > summary:hover {
background: #F3F4F6;
}
.home-mock[data-setup-minimized="1"] .setup-collapsible > summary .ico {
font-size: 18px;
line-height: 1;
}
.home-mock[data-setup-minimized="1"] .setup-collapsible > summary .ttl { flex: 1; }
.home-mock[data-setup-minimized="1"] .setup-collapsible > summary .ttl small {
color: var(--hp-text-secondary);
font-weight: 400;
margin-left: 6px;
}
.home-mock[data-setup-minimized="1"] .setup-collapsible > summary .chev {
font-size: 18px;
color: var(--hp-text-secondary);
transition: transform 160ms ease;
}
.home-mock[data-setup-minimized="1"] .setup-collapsible[open] > summary {
border-bottom-color: var(--hp-border);
background: #F3F4F6;
}
.home-mock[data-setup-minimized="1"] .setup-collapsible[open] > summary .chev {
transform: rotate(90deg);
}
/* Tighten the body padding so collapsed sections don't gain margin
when inside the white wrapper card. */
.home-mock[data-setup-minimized="1"] .setup-collapsible[open] > .automode-card,
.home-mock[data-setup-minimized="1"] .setup-collapsible[open] > .connector-tiles {
margin: 18px 22px 22px;
}
.home-mock[data-setup-minimized="1"] .setup-collapsible[open] > .section-label-flat {
padding: 14px 22px 0;
}
/* When a section's <details> is closed in minimize mode, the body
already auto-hides via the browser's <details> behaviour — no extra
rule needed. */
/* Minimize toggle in the blue hero, only present when onboarded. */
.home-mock .setup-minimize {
margin-top: 14px;
font-size: 13px;
color: rgba(255, 255, 255, 0.85);
}
.home-mock .setup-minimize button {
background: rgba(255, 255, 255, 0.10);
color: white;
border: 1px solid rgba(255, 255, 255, 0.25);
padding: 6px 14px;
border-radius: 6px;
font-size: 12px;
font-weight: 500;
cursor: pointer;
}
.home-mock .setup-minimize button:hover { background: rgba(255, 255, 255, 0.18); }
/* Callout, video-embed, news-hero, news-grid-*, news-cta — shared news
content vocabulary now lives in app/web/static/style-custom.css under
"News content vocabulary (shared)". Editing those rules in one place
updates /home perex, /news, and /admin/news preview together. */
.home-mock .install-done code {
background: rgba(15, 23, 42, 0.55);
border: 1px solid rgba(255, 255, 255, 0.18);
padding: 1px 6px;
border-radius: 4px;
font-family: var(--hp-font-mono);
font-size: 12px;
color: #FBBF24;
}
/* ─────────────────────────────────────────────────────────────────
Onboarding polish — friction fixes from internal usability testing.
Each block is tagged with its priority (P0/P1/P2) — P0 resolves the
highest-frequency confusion, P2 is nice-to-have polish.
───────────────────────────────────────────────────────────────── */
/* P0-1 — "Don't have a terminal open?" disclosure inside Step 1's
blue install-block. Yellow accent matches Claude footer mode dots
so it reads as a hint, not an error. */
.home-mock details.terminal-howto {
margin-top: 10px;
padding: 8px 12px;
background: rgba(251, 191, 36, 0.10);
border: 1px solid rgba(251, 191, 36, 0.30);
border-radius: 8px;
}
.home-mock details.terminal-howto > summary {
cursor: pointer;
list-style: none;
font-size: 12.5px;
font-weight: 600;
color: #FBBF24;
user-select: none;
}
.home-mock details.terminal-howto > summary::-webkit-details-marker { display: none; }
.home-mock details.terminal-howto > summary::before { content: "▸ "; margin-right: 4px; }
.home-mock details.terminal-howto[open] > summary::before { content: "▾ "; }
.home-mock .terminal-howto-body {
margin-top: 10px;
font-size: 12.5px;
color: rgba(255, 255, 255, 0.92);
line-height: 1.6;
}
.home-mock .terminal-howto-body p { margin: 0 0 6px; }
.home-mock .terminal-howto-body kbd {
background: rgba(255, 255, 255, 0.15);
border: 1px solid rgba(255, 255, 255, 0.30);
border-bottom-width: 2px;
border-radius: 4px;
padding: 1px 6px;
font-size: 11px;
font-family: var(--hp-font-mono);
color: white;
}
/* P0-3 — connector card time badge ("~5 min · self-serve") and the
post-copy "now paste into Step 2" hint with arrow back. */
.home-mock .connector-tile .ttl-row {
display: flex; align-items: center; justify-content: space-between; gap: 8px;
margin-bottom: 6px;
}
.home-mock .time-badge {
display: inline-flex;
align-items: center;
gap: 4px;
font-size: 11px;
font-weight: 600;
padding: 2px 8px;
border-radius: 999px;
background: var(--hp-primary-light);
color: var(--hp-primary-dark);
flex-shrink: 0;
}
.home-mock .time-badge.is-warn {
background: #FEF3C7;
color: #92400E;
}
.home-mock .copy-next-hint {
font-size: 12px;
color: var(--hp-primary-dark);
background: var(--hp-primary-light);
padding: 6px 10px;
border-radius: 6px;
margin-top: 6px;
display: none;
align-items: center;
gap: 6px;
line-height: 1.45;
}
.home-mock .copy-next-hint.is-visible { display: inline-flex; }
.home-mock .copy-next-hint code {
background: rgba(0, 0, 0, 0.06);
padding: 1px 5px;
border-radius: 3px;
font-family: var(--hp-font-mono);
font-size: 11px;
}
/* P1-8 — GWS gating note + Email-admin button. Yellow background
matches the same friction-level used by other "admin help likely"
surfaces (advanced setup warnings). */
.home-mock .gating-note {
font-size: 12px;
color: #92400E;
background: #FEF3C7;
border: 1px solid #FCD34D;
border-radius: 6px;
padding: 8px 10px;
margin-bottom: 10px;
line-height: 1.5;
}
.home-mock .email-admin {
display: inline-flex;
align-items: center;
gap: 6px;
background: white;
border: 1px solid var(--hp-border);
color: var(--hp-text-primary);
padding: 5px 12px;
border-radius: 6px;
font-size: 12px;
font-weight: 500;
text-decoration: none;
cursor: pointer;
align-self: flex-start;
margin-top: 6px;
}
.home-mock .email-admin:hover {
text-decoration: none;
border-color: var(--hp-primary);
color: var(--hp-primary-dark);
}
/* P1-6 — Auto-detect badge replaces the "Mark me as onboarded"
button as the primary affordance. Pulse dot signals it's actively
listening; the manual self-mark button stays as a fallback. */
.home-mock .auto-detect-badge {
display: inline-flex;
align-items: center;
gap: 8px;
margin-top: 16px;
background: rgba(255, 255, 255, 0.10);
border: 1px solid rgba(255, 255, 255, 0.20);
color: rgba(255, 255, 255, 0.92);
padding: 8px 14px;
border-radius: 8px;
font-size: 12.5px;
}
.home-mock .auto-detect-badge .pulse {
width: 8px; height: 8px;
border-radius: 50%;
background: #FBBF24;
box-shadow: 0 0 0 0 rgba(251, 191, 36, 0.7);
animation: agnes-pulse 1.6s infinite;
}
.home-mock .auto-detect-badge code {
background: rgba(0, 0, 0, 0.18);
padding: 1px 5px;
border-radius: 3px;
font-family: var(--hp-font-mono);
font-size: 11.5px;
}
@keyframes agnes-pulse {
0% { box-shadow: 0 0 0 0 rgba(251, 191, 36, 0.65); }
70% { box-shadow: 0 0 0 8px rgba(251, 191, 36, 0); }
100% { box-shadow: 0 0 0 0 rgba(251, 191, 36, 0); }
}
/* P0-2 — Post-CTA modal with "where to paste" 3-step guide. Modal
markup lives at body level; this styles the backdrop + card. The
.home-mock prefix is intentionally NOT used so the modal is
render-isolated from the home page's CSS variables. */
.cta-modal-backdrop {
position: fixed;
inset: 0;
background: rgba(15, 23, 42, 0.55);
-webkit-backdrop-filter: blur(2px);
backdrop-filter: blur(2px);
display: none;
align-items: center;
justify-content: center;
z-index: 1000;
padding: 20px;
}
.cta-modal-backdrop.is-open { display: flex; }
.cta-modal {
background: white;
border-radius: 14px;
padding: 28px 32px;
max-width: 520px;
width: 100%;
box-shadow: 0 24px 80px rgba(0, 0, 0, 0.35);
color: #111827;
font-family: inherit;
}
.cta-modal h2 {
font-size: 18px;
font-weight: 600;
margin: 0 0 6px;
color: #047857;
display: flex;
align-items: center;
gap: 8px;
}
.cta-modal .lead {
font-size: 13px;
color: #6B7280;
margin: 0 0 18px;
line-height: 1.55;
}
.cta-modal ol {
list-style: none;
padding: 0;
margin: 0 0 18px;
counter-reset: step;
}
.cta-modal ol li {
counter-increment: step;
display: flex;
gap: 14px;
align-items: flex-start;
padding: 12px;
background: #F9FAFB;
border-radius: 8px;
margin-bottom: 10px;
font-size: 13.5px;
line-height: 1.5;
}
.cta-modal ol li::before {
content: counter(step);
width: 26px; height: 26px;
border-radius: 50%;
background: #0073D1;
color: white;
font-weight: 700;
font-size: 12px;
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.cta-modal ol li code,
.cta-modal ol li kbd {
background: #fff;
border: 1px solid #E5E7EB;
padding: 1px 6px;
border-radius: 4px;
font-family: var(--hp-font-mono, ui-monospace, monospace);
font-size: 12px;
}
.cta-modal ol li kbd { border-bottom-width: 2px; }
.cta-modal ol li strong { display: block; margin-bottom: 4px; color: #111827; }
.cta-modal-foot {
display: flex; justify-content: space-between; align-items: center;
gap: 12px;
padding-top: 12px;
border-top: 1px solid #F3F4F6;
}
.cta-modal-foot .meta { font-size: 12px; color: #6B7280; }
.cta-modal-foot button {
background: #0073D1;
color: white;
border: none;
border-radius: 6px;
padding: 8px 18px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
font-family: inherit;
}
.cta-modal-foot button:hover { background: #0056A3; }
</style>
<div class="home-mock">
{% set display_name = (user.name or (user.email or "").split("@")[0] or "there") %}
<div class="install-hero">
{% if onboarded %}
<div class="eyebrow">Welcome back, {{ display_name }} — your workspace is ready</div>
<h1>You're set up — keep this page handy</h1>
<p class="lead">
Your local Agnes install is confirmed. The steps below stay useful for <strong>adding another machine</strong>, <strong>connecting more services</strong>, or <strong>turning on auto-accept mode</strong>. Skip whatever you don't need; nothing here re-runs unless you click it.
</p>
{% else %}
<div class="eyebrow">Welcome, {{ display_name }} — let's get you set up</div>
<h1>Connect Claude Code on your machine to your team's data</h1>
<p class="lead">
{{ instance_name or "Agnes" }} gives <strong>Claude Code</strong> on your computer access to your team's <strong>curated data, plugins, and shared knowledge</strong> — so you can ask questions and get answers in plain language, right from your terminal. This page walks you through the <strong>one-time setup (~10 minutes)</strong>. Everything it installs lives in your home folder (<code style="background: rgba(255,255,255,0.12); padding: 1px 6px; border-radius: 4px; font-family: var(--hp-font-mono); font-size: 12.5px;">~/Agnes</code>) and can be removed in one command.
</p>
{% endif %}
{% if onboarded %}
<div class="install-done" role="status" aria-live="polite">
<span class="check" aria-hidden="true">&#x2705;</span>
<span><strong>Step 1, 2 &amp; 3 done</strong> — Claude Code installed, auto-mode set, Agnes ready in <code>~/Agnes</code>. The full install steps stay one click away under the offboard control below.</span>
</div>
{% endif %}
{% if not onboarded %}
<div class="install-block">
<div class="label">Step 1 — install Claude Code</div>
<div class="os-tabs" role="tablist" aria-label="Operating system">
<button type="button" role="tab" class="os-tab is-active"
data-os-tab="unix" aria-selected="true">macOS / Linux / WSL</button>
<button type="button" role="tab" class="os-tab"
data-os-tab="windows" aria-selected="false">Windows (PowerShell)</button>
</div>
<div class="install-cmd" role="tabpanel" data-os-panel="unix">
<span class="multiline" id="install-cmd-claude-unix">curl -fsSL https://claude.ai/install.sh | bash</span>
<button class="copy-btn" data-copy-target="install-cmd-claude-unix">Copy</button>
</div>
<div class="install-cmd" role="tabpanel" data-os-panel="windows" hidden>
<span class="multiline" id="install-cmd-claude-windows">irm https://claude.ai/install.ps1 | iex</span>
<button class="copy-btn" data-copy-target="install-cmd-claude-windows">Copy</button>
</div>
{# P0-1 — terminal-howto disclosure. Two panels (unix / windows)
that flip in lockstep with the install-cmd OS tabs above. #}
<details class="terminal-howto">
<summary>Don't have a terminal open? — show how</summary>
<div class="terminal-howto-body" data-howto-panel="unix">
<p><strong>macOS:</strong> press <kbd></kbd> + <kbd>Space</kbd>, type <kbd>Terminal</kbd>, press <kbd>Enter</kbd>.</p>
<p><strong>Linux:</strong> press <kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>T</kbd> (most distros), or open the apps menu and search "Terminal".</p>
<p><strong>WSL:</strong> open the Windows Start menu, search "Ubuntu" (or your installed distro), press <kbd>Enter</kbd>.</p>
<p>Paste the command above with <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>V</kbd> (Linux/WSL) or <kbd></kbd> + <kbd>V</kbd> (macOS), then press <kbd>Enter</kbd>.</p>
</div>
<div class="terminal-howto-body" data-howto-panel="windows" hidden>
<p><strong>Windows:</strong> press <kbd>Win</kbd> + <kbd>R</kbd>, type <kbd>powershell</kbd>, press <kbd>Enter</kbd>. (Or: open Start menu, type "PowerShell".)</p>
<p>Paste the command above with <kbd>Ctrl</kbd> + <kbd>V</kbd> and press <kbd>Enter</kbd>.</p>
</div>
</details>
<div class="install-note">
Verify with <code>claude --version</code>. Sign in once with <code>claude</code> and complete the OAuth flow.
Don't have a Claude license yet? See <a href="/setup-advanced#claude-plan">plan options on /setup-advanced</a> (Pro / Max 5× / Max 20×).
</div>
</div>
{% if home_automode.show %}
<div class="install-block">
<div class="label">Step 2 — turn on auto-mode (recommended before Step 3)</div>
<div class="install-note">
In the Claude Code session you just signed into, press <strong>Shift + Tab</strong>. Claude cycles modes: default → <strong>auto-accept edits</strong> → plan mode → default; the footer shows <code>⏵⏵</code> when auto-accept is on. On the first cycle to auto-accept, Claude asks whether to make it the default — say <strong>yes</strong>. Closed the session already? Run <code>claude</code> again, then press <strong>Shift + Tab</strong>.
<br><br>
Want full auto-approve including Bash? See <a href="/setup-advanced#yolo">YOLO mode</a> on /setup-advanced — pairs <code>--dangerously-skip-permissions</code> with a reviewed <code>~/.claude/settings.local.json</code> allowlist. Skip if you're not sure.
</div>
</div>
{% endif %}
<div class="install-block">
<div class="label">Step 3 — install Agnes from inside Claude Code</div>
<p class="setup-cta-lead">
Click the button — {{ instance_name or "Agnes" }} <strong>creates a 90-day login token</strong>, copies a ready-to-paste setup script to your clipboard, and a follow-up popup tells you exactly where to paste it. The script bootstraps everything in <code>~/Agnes</code> once Claude Code receives it.
</p>
<div class="setup-cta-row">
<button type="button" id="setupClaudeBtn" class="btn-setup-primary" onclick="setupNewClaude(this)">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
</svg>
Setup a new Claude Code
</button>
<span class="setup-cta-meta">
<span class="setup-cta-hint">Valid 90 days · token stays in clipboard only</span>
</span>
</div>
<div id="setupClaudeError" class="setup-error" role="alert" style="display:none;"></div>
<details class="manual-fallback">
<summary>Or paste manually (preview the script)</summary>
<div class="manual-preview-wrap">
{% with preview_mode=True %}
{% include "_claude_setup_instructions.jinja" %}
{% endwith %}
</div>
<div class="install-note">
The preview above is the exact text the button copies; the placeholder is replaced with a real token at click time. Don't create <code>~/Agnes/Projects/</code> manually — the bundled plugin offers to set it up after install.
</div>
</details>
</div>
{% endif %}
{# P1-6 — auto-detect badge is the PRIMARY affordance after the
install-script copy: agnes-init's first POST to
/api/me/onboarded flips state automatically and the page
reloads. The manual "Mark me as onboarded" button below it
stays as a fallback when auto-flip never lands. #}
{% if not onboarded %}
<div class="auto-detect-badge" role="status" aria-live="polite">
<span class="pulse" aria-hidden="true"></span>
<span>Waiting for your first <code>agnes pull</code> — auto-detects within ~30 s of the setup script finishing.</span>
</div>
{% endif %}
{# Self-mark control lives inside the blue hero in both states.
When onboarded, the install steps above are hidden so this is
the only thing rendered below the lead paragraph. #}
<div class="self-mark">
{% if onboarded %}
Wiped your workspace or want the full setup view back?
<button id="self-mark-btn" type="button"
data-target-onboarded="false"
data-target-source="self_unmark">Mark me as offboarded</button>
{% else %}
Already set this up?
<button id="self-mark-btn" type="button"
data-target-onboarded="true"
data-target-source="self_acknowledged">Mark me as onboarded</button>
{% endif %}
<span id="self-mark-status" class="status" role="status" aria-live="polite"></span>
</div>
{% if onboarded %}
{# User-controlled minimize toggle for Connect-your-tools.
Default OFF (section renders flat). State persists in
localStorage so the choice is per-device. The agnes-init
auto-flip of users.onboarded never triggers a collapse on
its own — only an explicit click here does. The auto-mode
block used to be a peer collapsible (`step3`); it now lives
inside the install-hero as Step 2 and is not collapsible. #}
<div class="setup-minimize">
<button id="setupMinimizeToggle" type="button" aria-pressed="false">
Minimize setup view
</button>
</div>
{% endif %}
</div>
{# Auto-mode card used to live here as a `<details>` reference block;
moved into the install-hero as the new Step 2 so users enable it
BEFORE Step 3's install runs ~20 commands. Gated by the same
`home_automode.show` flag at the call site. #}
<details class="setup-collapsible" data-section="connectors" open>
<summary>
<span class="ico" aria-hidden="true">&#x1F517;</span>
<span class="ttl">Connect your tools <small>(Asana / Google Workspace / Atlassian)</small></span>
<span class="chev" aria-hidden="true">&rsaquo;</span>
</summary>
<div class="section-label section-label-flat">Once Agnes is installed — connect your tools</div>
<div class="connector-tiles">
<div class="connector-tile">
<span class="ico">&#x2705;</span>
{# P0-3 — title row + time-badge + post-copy hint. The hint
container is rendered hidden; the JS reveals it after the
copy succeeds, then auto-hides after 8 s. #}
<div class="ttl-row">
<span class="ttl">Asana</span>
<span class="time-badge">~5 min · self-serve</span>
</div>
<div class="desc">Read tasks and projects, comment, create updates — Claude works alongside your project boards without leaving the terminal.</div>
<div class="connector-actions">
<button class="connector-copy" data-copy-target="asana-prompt" data-connector="Asana">Copy prompt</button>
<div class="copy-next-hint" data-hint-for="Asana">
<span>&#x2705; Copied. Now paste into Claude Code — run <code>claude</code> in your terminal, then paste &amp; press Enter.</span>
</div>
<details class="connector-preview">
<summary>Show prompt</summary>
{# Asana prompt body sourced from app/web/connector_prompts.py
(`asana_prompt()`). Same string the main setup script
inlines in step 9, so the two surfaces stay in lockstep. #}
<div class="card-mini-cmd"><code id="asana-prompt">{{ connector_prompts.asana }}</code></div>
</details>
</div>
</div>
<div class="connector-tile">
<span class="ico">&#x1F4DA;</span>
{# P0-3 + P1-8 — Google Workspace tile. Time badge warns when
the operator hasn't provisioned a shared OAuth app (forces
the user to set up GCP themselves, which is a ~20-min
clickops detour). The gating-note + email-admin button
appear in that same un-configured branch so the user has
a way out before copying. #}
<div class="ttl-row">
<span class="ttl">Google Workspace</span>
{% if gws_oauth.configured %}
<span class="time-badge">~5 min · self-serve</span>
{% else %}
<span class="time-badge is-warn">~20 min · admin help likely</span>
{% endif %}
</div>
<div class="desc">Drive, Calendar, Gmail, Docs, Sheets, Chat — Claude reads and acts across your work account via the official <code>gws</code> CLI.</div>
{% if not gws_oauth.configured %}
<div class="gating-note">
<strong>Heads up:</strong> your Agnes admin hasn't provisioned a shared Google Cloud OAuth app yet, so this connector needs GCP project setup (creating an OAuth client, enabling APIs). It's fastest to ask your admin first — the button below pre-fills the email.
</div>
{% endif %}
<div class="connector-actions">
<button class="connector-copy" data-copy-target="gws-prompt" data-connector="Google Workspace">Copy prompt</button>
{% if not gws_oauth.configured and instance_admin_email %}
<a class="email-admin" href="mailto:{{ instance_admin_email }}?subject=Agnes%20%E2%80%94%20Google%20Workspace%20OAuth%20setup&amp;body=Hi%20%E2%80%94%20I'd%20like%20to%20connect%20Google%20Workspace%20in%20Agnes%20but%20it%20looks%20like%20a%20shared%20OAuth%20app%20isn't%20provisioned%20yet.%20Could%20you%20set%20it%20up%20for%20our%20instance%3F%20Thanks!">
&#x2709;&#xFE0F; Email admin
</a>
{% endif %}
<div class="copy-next-hint" data-hint-for="Google Workspace">
<span>&#x2705; Copied. Now paste into Claude Code — run <code>claude</code> in your terminal, then paste &amp; press Enter.</span>
</div>
<details class="connector-preview">
<summary>Show prompt</summary>
<div class="card-mini-cmd"><code id="gws-prompt">{{ connector_prompts.gws }}</code></div>
</details>
</div>
</div>
<div class="connector-tile">
<span class="ico">&#x1F39F;&#xFE0F;</span>
<div class="ttl-row">
<span class="ttl">Atlassian (Jira / Confluence)</span>
<span class="time-badge">~7 min · self-serve</span>
</div>
<div class="desc">Read and write Jira issues, search Confluence pages — Claude pulls ticket context and posts updates without leaving the workspace.</div>
<div class="connector-actions">
<button class="connector-copy" data-copy-target="jira-prompt" data-connector="Atlassian">Copy prompt</button>
<div class="copy-next-hint" data-hint-for="Atlassian">
<span>&#x2705; Copied. Now paste into Claude Code — run <code>claude</code> in your terminal, then paste &amp; press Enter.</span>
</div>
<details class="connector-preview">
<summary>Show prompt</summary>
<div class="card-mini-cmd"><code id="jira-prompt">{{ connector_prompts.atlassian }}</code></div>
</details>
</div>
</div>
</div>
</details>
<div class="section-label">Want to look around first?</div>
<p class="look-around-lead">You don't need Agnes installed locally to browse what's available. Anything you bookmark or subscribe to will be there waiting after you set Agnes up.</p>
<div class="what-is look-around-grid">
<a class="what-is-item" href="/marketplace">
<span class="ico">&#x1F9E9;</span>
<div class="ttl">Plugin marketplace <span class="arrow">&rarr;</span></div>
<div class="desc">Curated and community-built plugins for Claude Code — Asana, Jira, Google Workspace, and more. Browse, install, sync.</div>
</a>
<a class="what-is-item" href="/catalog">
<span class="ico">&#x1F4E6;</span>
<div class="ttl">Curated data packages <span class="arrow">&rarr;</span></div>
<div class="desc">Tables, schema, and metric definitions your team has registered. Subscribe and Claude can query them with documented business rules.</div>
</a>
{# Corporate memory + Activity center are both admin-only — matches
the top-nav gating logic (the "Memory" link is hidden for
non-admin in _app_header.html, and the /corporate-memory route
is `require_admin`). Without this gate non-admin users would
see a Corporate memory tile that 403s when clicked. #}
{% if is_admin %}
<a class="what-is-item" href="/corporate-memory">
<span class="ico">&#x1F9E0;</span>
<div class="ttl">Corporate memory <span class="arrow">&rarr;</span></div>
<div class="desc">Shared analyst knowledge and prior solutions to draw from. Searchable, versioned, fed back into Claude's context on demand.</div>
</a>
<a class="what-is-item" href="/activity-center">
<span class="ico">&#x1F4C8;</span>
<div class="ttl">Activity center <span class="arrow">&rarr;</span></div>
<div class="desc">Per-user analytics on Agnes adoption across your team. Sessions, plugin installs, prompt patterns.</div>
</a>
{% endif %}
</div>
<a class="advanced-pointer" href="/setup-advanced">
<span class="ico">&#x1F6E0;&#xFE0F;</span>
<div class="advanced-pointer-text">
<strong>Going deeper — Advanced setup</strong>
VS Code split-terminal layout, recommended Claude Code plugins (with copy-able install commands), multi-model second opinions (Codex + Gemini), custom skills + rules + hooks, project workflows, plan tier guidance.
</div>
<span class="arrow">&rarr;</span>
</a>
{% if news_intro %}
<section class="home-news">
<header class="home-news-head">
<h2>What's new</h2>
<a class="home-news-more" href="/news">Read more &rarr;</a>
</header>
<div class="home-news-body">{{ news_intro | safe }}</div>
</section>
{% endif %}
</div>
{# P0-2 — Post-CTA modal. Opens after the shared CTA include below has
created the token + copied the script. _claude_setup_cta.jinja still
owns the token request + clipboard write; this modal layers on top
with a 3-step "where to paste" guide. Lives at body level so the
home-mock styles don't bleed into it. #}
{% if not onboarded %}
<div class="cta-modal-backdrop" id="cta-modal-backdrop" role="dialog" aria-modal="true" aria-labelledby="cta-modal-title" hidden>
<div class="cta-modal">
<h2 id="cta-modal-title"><span aria-hidden="true">&#x2705;</span> Setup script copied to clipboard</h2>
<p class="lead">Now paste it into Claude Code on your machine — three steps:</p>
<ol>
<li>
<div>
<strong>Open a terminal</strong>
macOS: <kbd></kbd>+<kbd>Space</kbd>, type "Terminal". Windows: <kbd>Win</kbd>+<kbd>R</kbd>, type <code>powershell</code>. Linux: <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>T</kbd>.
</div>
</li>
<li>
<div>
<strong>Start Claude Code</strong>
Type <code>claude</code> and press <kbd>Enter</kbd>. You'll see a prompt waiting for input.
</div>
</li>
<li>
<div>
<strong>Paste &amp; press Enter</strong>
macOS: <kbd></kbd>+<kbd>V</kbd>. Windows/Linux: <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>V</kbd>. Claude runs the setup and tells you when it's done.
</div>
</li>
</ol>
<div class="cta-modal-foot">
<span class="meta">Token is in clipboard only — never displayed here.</span>
<button type="button" id="cta-modal-close">Got it</button>
</div>
</div>
</div>
{% endif %}
{# Shared "Setup a new Claude Code" CTA behaviour — provides the JS that
POSTs /auth/tokens, copies the rendered instructions to the clipboard,
and falls back to a modal when the clipboard API is blocked. The button
above (id="setupClaudeBtn") is the primary trigger. #}
{% include "_claude_setup_cta.jinja" %}
<script>
(function () {
function wireCopy(btn) {
btn.addEventListener('click', function () {
var src = document.getElementById(btn.getAttribute('data-copy-target'));
if (!src) return;
// textContent (not innerText) so collapsed <details> content still
// copies — innerText returns "" for nodes whose ancestor has
// display:none (which is what closed <details> applies).
var raw = src.textContent || '';
var text = raw.replace(/ /g, ' ');
navigator.clipboard.writeText(text).then(function () {
var orig = btn.textContent;
btn.textContent = 'Copied';
setTimeout(function () { btn.textContent = orig; }, 1500);
}).catch(function () { btn.textContent = 'Copy failed'; });
});
}
document.querySelectorAll('.copy-btn[data-copy-target]').forEach(wireCopy);
// P0-3 + P2-12 — Connector copy buttons. Three things on click:
// 1) copy the prompt (same textContent trick so closed <details>
// still copies);
// 2) flip the button to "✓ Copied" + disabled for 8 s so the user
// stops mashing it while figuring out where to paste;
// 3) reveal a paste hint pointing the user at Claude Code.
document.querySelectorAll('.connector-copy[data-copy-target]').forEach(function (btn) {
btn.addEventListener('click', function () {
var src = document.getElementById(btn.getAttribute('data-copy-target'));
if (!src) return;
var raw = src.textContent || '';
var connector = btn.getAttribute('data-connector') || '';
var hint = connector
? document.querySelector('.copy-next-hint[data-hint-for="' + connector + '"]')
: null;
navigator.clipboard.writeText(raw).then(function () {
var orig = btn.textContent;
btn.classList.add('copied');
btn.textContent = '✓ Copied';
btn.disabled = true;
if (hint) hint.classList.add('is-visible');
setTimeout(function () {
btn.classList.remove('copied');
btn.textContent = orig;
btn.disabled = false;
if (hint) hint.classList.remove('is-visible');
}, 8000);
}).catch(function () { btn.textContent = 'Copy failed'; });
});
});
// OS tab switching for Step 1. Flips both the command panel AND the
// P0-1 terminal-howto body so the howto matches the active OS.
document.querySelectorAll('.os-tab[data-os-tab]').forEach(function (tab) {
tab.addEventListener('click', function () {
var target = tab.getAttribute('data-os-tab');
var scope = tab.closest('.install-block') || document;
scope.querySelectorAll('.os-tab[data-os-tab]').forEach(function (t) {
var on = t.getAttribute('data-os-tab') === target;
t.classList.toggle('is-active', on);
t.setAttribute('aria-selected', on ? 'true' : 'false');
});
scope.querySelectorAll('[data-os-panel]').forEach(function (p) {
if (p.getAttribute('data-os-panel') === target) {
p.removeAttribute('hidden');
} else {
p.setAttribute('hidden', '');
}
});
// P0-1 — flip the howto bodies in lockstep.
scope.querySelectorAll('[data-howto-panel]').forEach(function (p) {
if (p.getAttribute('data-howto-panel') === target) {
p.removeAttribute('hidden');
} else {
p.setAttribute('hidden', '');
}
});
});
});
// P0-2 — Post-CTA modal. _claude_setup_cta.jinja owns the click
// handler that POSTs /auth/tokens + copies the script; we wait for
// its success signal (agnes:setup-script-copied custom event) and
// then open the "where to paste" guide. Without the event the modal
// simply never opens — the include's own fallback paths handle
// older browsers / blocked clipboard.
var ctaModal = document.getElementById('cta-modal-backdrop');
var ctaModalClose = document.getElementById('cta-modal-close');
function openCtaModal() {
if (!ctaModal) return;
ctaModal.removeAttribute('hidden');
ctaModal.classList.add('is-open');
if (ctaModalClose) ctaModalClose.focus();
}
function closeCtaModal() {
if (!ctaModal) return;
ctaModal.classList.remove('is-open');
ctaModal.setAttribute('hidden', '');
var setupBtn = document.getElementById('setupClaudeBtn');
if (setupBtn) setupBtn.focus();
}
if (ctaModal) {
document.addEventListener('agnes:setup-script-copied', openCtaModal);
if (ctaModalClose) ctaModalClose.addEventListener('click', closeCtaModal);
ctaModal.addEventListener('click', function (ev) {
if (ev.target === ctaModal) closeCtaModal();
});
document.addEventListener('keydown', function (ev) {
if (ev.key === 'Escape' && ctaModal.classList.contains('is-open')) closeCtaModal();
});
}
var btn = document.getElementById('self-mark-btn');
var status = document.getElementById('self-mark-status');
if (!btn) return;
btn.addEventListener('click', function () {
// Direction comes from data-attrs the template sets per render —
// onboarded view → flip to FALSE (offboard), not-onboarded → flip to TRUE.
var targetOnboarded = btn.getAttribute('data-target-onboarded') === 'true';
var targetSource = btn.getAttribute('data-target-source') || 'self_acknowledged';
btn.disabled = true;
status.textContent = targetOnboarded ? 'Marking…' : 'Resetting…';
fetch('/api/me/onboarded', {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ source: targetSource, onboarded: targetOnboarded }),
}).then(function (resp) {
if (resp.ok) {
status.textContent = 'Done. Reloading…';
window.location.reload();
} else {
status.textContent = 'Failed (' + resp.status + '). Try again.';
btn.disabled = false;
}
}).catch(function () {
status.textContent = 'Network error. Try again.';
btn.disabled = false;
});
});
// ── Minimize-setup toggle ────────────────────────────────────────
// Default OFF: sections render flat (no <summary> visible).
// ON: data-setup-minimized="1" on .home-mock activates the slim
// gray summary bars; <details> open/close handles per-section
// expansion. Per-device via localStorage; survives reloads but
// resets on a new machine — which is correct (the user might
// want the full reference there).
var KEY = 'agnes_home_setup_minimized';
var mockEl = document.querySelector('.home-mock');
var minToggle = document.getElementById('setupMinimizeToggle');
var collapsibles = document.querySelectorAll('.setup-collapsible');
function applyMinimize(on) {
if (!mockEl) return;
if (on) {
mockEl.setAttribute('data-setup-minimized', '1');
collapsibles.forEach(function (d) { d.removeAttribute('open'); });
if (minToggle) {
minToggle.textContent = 'Show full setup view';
minToggle.setAttribute('aria-pressed', 'true');
}
} else {
mockEl.removeAttribute('data-setup-minimized');
collapsibles.forEach(function (d) { d.setAttribute('open', ''); });
if (minToggle) {
minToggle.textContent = 'Minimize setup view';
minToggle.setAttribute('aria-pressed', 'false');
}
}
}
// Initial state — only when the toggle exists (= onboarded view).
if (minToggle) {
try { applyMinimize(localStorage.getItem(KEY) === '1'); }
catch (e) { /* ignore localStorage failures (private mode) */ }
minToggle.addEventListener('click', function () {
var nowOn = mockEl.getAttribute('data-setup-minimized') !== '1';
try { localStorage.setItem(KEY, nowOn ? '1' : '0'); } catch (e) {}
applyMinimize(nowOn);
});
}
})();
</script>
{% endblock %}