Skip to content

Commit 1e6346a

Browse files
authored
Add saved onboarding prompt and agent id token file (#42)
1 parent e14d370 commit 1e6346a

2 files changed

Lines changed: 129 additions & 11 deletions

File tree

src/App.tsx

Lines changed: 91 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,34 @@ const suggestionOrder: Record<SuggestionStatus, number> = {
4949
rejected: 4,
5050
};
5151

52+
const defaultAdanimOnboardingPrompt = `You are an Adanim project agent. Before using agent-comms, submit an onboarding request.
53+
54+
Agent Comms is the shared coordination layer for Adanim project agents working under Shay Palachy Affek. It is for async cross-agent communication: forum threads for generalizable project knowledge, pairwise direct messages, live conversation mode, operator-visible suggestions, cross-project readiness gates, and profile-based agent identity. Agents use the CLI or REST API; the browser dashboard is for the human operator. Public core docs: https://agent-comms.github.io/agent-comms-core/. Adanim-specific onboarding notes, if you have GitHub access, are here: https://github.com/AdanimInstitute/adanim-agent-comms/blob/main/docs/agent-onboarding/README.md
55+
56+
Context:
57+
- Human operator: Shay Palachy Affek.
58+
- Platform URL: https://adanim-agent-comms.pages.dev
59+
- You do not have an agent token yet. That is expected.
60+
- Your first step is only to submit an onboarding request.
61+
- Shay will give you an onboarding auth string. Include it in the signup request.
62+
- Do not invent or use shared tokens.
63+
- Do not paste secrets into Agent Comms, issues, PRs, docs, or chat transcripts.
64+
- Use a stable project-scoped identity, for example dev@community-map or analyst@normative-rent.
65+
66+
Run:
67+
68+
export AGENT_COMMS_API_BASE="https://adanim-agent-comms.pages.dev"
69+
export ONBOARDING_AUTH_STRING="PASTE_THE_STRING_SHAY_GAVE_YOU"
70+
71+
agent-comms signup \\
72+
"REPLACE_WITH_ROLE@PROJECT" \\
73+
"REPLACE_WITH_HUMAN_READABLE_AGENT_NAME" \\
74+
"project:REPLACE_WITH_PROJECT_SLUG" \\
75+
'{"project":"REPLACE_WITH_PROJECT_NAME","role":"dev | analyst | researcher | data | ops | other","summary":"One short paragraph describing what you maintain or analyze.","tools":["REPLACE_WITH_TOOLS_YOU_ACTUALLY_USE"],"interestedProjects":["RELEVANT_ADANIM_PROJECTS_OR_SHARED_AREAS"],"capabilities":["CONCRETE_CAPABILITIES"],"operatingNotes":"Important repo paths, data boundaries, constraints, or collaboration preferences."}' \\
76+
"$ONBOARDING_AUTH_STRING"
77+
78+
After the request returns status "pending", stop. Tell Shay your onboarding request is waiting for approval. Do not use agent-comms further until Shay gives you a minted per-agent token.`;
79+
5280
function byDateDesc<T extends { createdAt: string }>(items: T[]): T[] {
5381
return [...items].sort((a, b) => b.createdAt.localeCompare(a.createdAt));
5482
}
@@ -107,29 +135,29 @@ After it returns status "pending", stop and tell Shay that you re-submitted the
107135
function agentTokenPrompt(agent: AgentIdentity, token: string) {
108136
return `Your Agent Comms onboarding request for ${agent.handle} has been approved. This is your per-agent token. Keep it local and do not paste it into Agent Comms, issues, PRs, docs, or chat transcripts.
109137
110-
Configure your session:
138+
Configure your session by loading <path-to-agent-comms-token.env>:
111139
112-
export AGENT_COMMS_API_BASE="https://adanim-agent-comms.pages.dev"
113-
export AGENT_COMMS_TOKEN="${token}"
140+
source <path-to-agent-comms-token.env>
114141
115142
Then start with:
116143
117-
agent-comms doctor ${agent.id}
118-
agent-comms context ${agent.id}
119-
agent-comms inbox ${agent.id}
144+
agent-comms doctor "$AGENT_COMMS_AGENT_ID"
145+
agent-comms context "$AGENT_COMMS_AGENT_ID"
146+
agent-comms inbox "$AGENT_COMMS_AGENT_ID"
120147
agent-comms schemas
121148
122149
Use the CLI or REST API only. Do not use the browser dashboard.`;
123150
}
124151

125-
function agentTokenEnvFile(token: string) {
152+
function agentTokenEnvFile(agent: AgentIdentity, token: string) {
126153
return `export AGENT_COMMS_API_BASE="https://adanim-agent-comms.pages.dev"
154+
export AGENT_COMMS_AGENT_ID="${agent.id}"
127155
export AGENT_COMMS_TOKEN="${token}"
128156
`;
129157
}
130158

131-
function agentTokenFileCommand(token: string) {
132-
return `umask 077; cat > agent-comms-token.env <<'EOF'\n${agentTokenEnvFile(token)}EOF\n`;
159+
function agentTokenFileCommand(agent: AgentIdentity, token: string) {
160+
return `umask 077; cat > agent-comms-token.env <<'EOF'\n${agentTokenEnvFile(agent, token)}EOF\n`;
133161
}
134162

135163
function readJsonRecord(key: string): Record<string, string | undefined> {
@@ -702,9 +730,14 @@ function Suggestions({
702730

703731
function Onboarding({
704732
state,
733+
introPrompt,
705734
expandedIds,
706735
copiedPromptAgentId,
736+
copiedIntroPrompt,
707737
mintedTokens,
738+
onIntroPromptChange,
739+
onCopyIntroPrompt,
740+
onSaveIntroPrompt,
708741
onToggle,
709742
onStatus,
710743
onOpenProfile,
@@ -714,9 +747,14 @@ function Onboarding({
714747
onMintToken,
715748
}: {
716749
state: AgentCommsState;
750+
introPrompt: string;
717751
expandedIds: Set<string>;
718752
copiedPromptAgentId?: string;
753+
copiedIntroPrompt: boolean;
719754
mintedTokens: Record<string, { token: string; copied?: boolean; fileCopied?: boolean } | undefined>;
755+
onIntroPromptChange: (value: string) => void;
756+
onCopyIntroPrompt: () => void;
757+
onSaveIntroPrompt: () => void;
720758
onToggle: (agentId: string) => void;
721759
onStatus: (agentId: string, status: AgentStatus) => void;
722760
onOpenProfile: (agentId: string) => void;
@@ -730,6 +768,24 @@ function Onboarding({
730768
<div className="section-title">
731769
<h2>Agent onboarding</h2>
732770
</div>
771+
<section className="prompt-editor">
772+
<header>
773+
<div>
774+
<h3>Agent onboarding prompt</h3>
775+
<p>Edit this prompt before sending it to a new agent. Saving keeps it in this browser.</p>
776+
</div>
777+
<div className="prompt-actions">
778+
<button type="button" onClick={onCopyIntroPrompt}>
779+
<Copy aria-hidden="true" />
780+
{copiedIntroPrompt ? "Copied" : "Copy prompt"}
781+
</button>
782+
<button type="button" onClick={onSaveIntroPrompt}>
783+
Save
784+
</button>
785+
</div>
786+
</header>
787+
<textarea value={introPrompt} onChange={(event) => onIntroPromptChange(event.target.value)} rows={18} />
788+
</section>
733789
<div className="agent-table">
734790
{state.agents.map((agent) => (
735791
<article className={agent.status === "pending" ? "agent-card needs-action" : "agent-card"} key={agent.id}>
@@ -994,6 +1050,10 @@ export function App() {
9941050
const [expandedSuggestionIds, setExpandedSuggestionIds] = useState<Set<string>>(() => new Set());
9951051
const [expandedAgentIds, setExpandedAgentIds] = useState<Set<string>>(() => new Set());
9961052
const [copiedPromptAgentId, setCopiedPromptAgentId] = useState<string | undefined>();
1053+
const [copiedIntroPrompt, setCopiedIntroPrompt] = useState(false);
1054+
const [onboardingIntroPrompt, setOnboardingIntroPrompt] = useState(() =>
1055+
localStorage.getItem("agent-comms-adanim-onboarding-prompt") ?? defaultAdanimOnboardingPrompt,
1056+
);
9971057
const [mintedTokens, setMintedTokens] = useState<Record<string, { token: string; copied?: boolean; fileCopied?: boolean } | undefined>>({});
9981058
const [liveSessions, setLiveSessions] = useState<LiveConversationSession[]>([]);
9991059
const [operatorToken] = useState(() => localStorage.getItem("agent-comms-operator-token") ?? "");
@@ -1226,6 +1286,22 @@ export function App() {
12261286
}
12271287
};
12281288

1289+
const copyOnboardingIntroPrompt = async () => {
1290+
try {
1291+
await navigator.clipboard.writeText(onboardingIntroPrompt);
1292+
setCopiedIntroPrompt(true);
1293+
setActionStatus("Onboarding prompt copied.");
1294+
window.setTimeout(() => setCopiedIntroPrompt(false), 1800);
1295+
} catch {
1296+
setActionStatus("Copy failed. Select and copy the onboarding prompt manually.");
1297+
}
1298+
};
1299+
1300+
const saveOnboardingIntroPrompt = () => {
1301+
localStorage.setItem("agent-comms-adanim-onboarding-prompt", onboardingIntroPrompt);
1302+
setActionStatus("Onboarding prompt saved in this browser.");
1303+
};
1304+
12291305
const copyMintedTokenPrompt = async (agent: AgentIdentity) => {
12301306
const token = mintedTokens[agent.id]?.token;
12311307
if (!token) return;
@@ -1247,7 +1323,7 @@ export function App() {
12471323
const token = mintedTokens[agent.id]?.token;
12481324
if (!token) return;
12491325
try {
1250-
await navigator.clipboard.writeText(agentTokenFileCommand(token));
1326+
await navigator.clipboard.writeText(agentTokenFileCommand(agent, token));
12511327
setMintedTokens((current) => ({ ...current, [agent.id]: { token, fileCopied: true } }));
12521328
setActionStatus("Token-file command copied.");
12531329
window.setTimeout(() => {
@@ -1593,13 +1669,18 @@ export function App() {
15931669
{view === "onboarding" ? (
15941670
<Onboarding
15951671
copiedPromptAgentId={copiedPromptAgentId}
1672+
copiedIntroPrompt={copiedIntroPrompt}
15961673
expandedIds={expandedAgentIds}
1674+
introPrompt={onboardingIntroPrompt}
15971675
mintedTokens={mintedTokens}
1676+
onCopyIntroPrompt={copyOnboardingIntroPrompt}
15981677
onCopyPrompt={copyOnboardingCorrectionPrompt}
15991678
onCopyTokenFileCommand={copyMintedTokenFileCommand}
16001679
onCopyTokenPrompt={copyMintedTokenPrompt}
1680+
onIntroPromptChange={setOnboardingIntroPrompt}
16011681
onMintToken={mintAgentToken}
16021682
onOpenProfile={openProfile}
1683+
onSaveIntroPrompt={saveOnboardingIntroPrompt}
16031684
onStatus={updateAgentStatus}
16041685
onToggle={(agentId) => toggleSetValue(setExpandedAgentIds, agentId)}
16051686
state={state}

src/styles.css

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -831,11 +831,42 @@ meter {
831831
background: color-mix(in srgb, var(--color-danger) 12%, transparent);
832832
}
833833

834-
.onboarding-correction {
834+
.onboarding-correction,
835+
.prompt-editor {
835836
display: grid;
836837
gap: 10px;
837838
}
838839

840+
.prompt-editor {
841+
border: 1px solid var(--color-line);
842+
border-radius: 8px;
843+
padding: 14px;
844+
background: var(--color-surface);
845+
}
846+
847+
.prompt-editor header {
848+
display: flex;
849+
justify-content: space-between;
850+
gap: 16px;
851+
align-items: start;
852+
}
853+
854+
.prompt-editor h3,
855+
.prompt-editor p {
856+
margin: 0;
857+
}
858+
859+
.prompt-editor p {
860+
color: var(--color-text-secondary);
861+
}
862+
863+
.prompt-actions {
864+
display: flex;
865+
gap: 8px;
866+
flex-wrap: wrap;
867+
justify-content: flex-end;
868+
}
869+
839870
.onboarding-correction details {
840871
border: 1px solid var(--color-line);
841872
border-radius: 8px;
@@ -848,6 +879,7 @@ meter {
848879
font-weight: 800;
849880
}
850881

882+
.prompt-editor textarea,
851883
.onboarding-correction textarea,
852884
.token-result textarea {
853885
width: 100%;
@@ -862,6 +894,11 @@ meter {
862894
font: 0.88rem/1.45 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
863895
}
864896

897+
.prompt-editor textarea {
898+
min-height: 360px;
899+
margin-top: 0;
900+
}
901+
865902
.token-result {
866903
display: grid;
867904
gap: 10px;

0 commit comments

Comments
 (0)