fix: read task context from ctx.context, inject authToken, fix prompt auth#26
Open
mattverlaque wants to merge 1 commit intoNousResearch:mainfrom
Open
fix: read task context from ctx.context, inject authToken, fix prompt auth#26mattverlaque wants to merge 1 commit intoNousResearch:mainfrom
mattverlaque wants to merge 1 commit intoNousResearch:mainfrom
Conversation
kit-floating
pushed a commit
to kit-floating/hermes-paperclip-adapter
that referenced
this pull request
Apr 5, 2026
Brings the Hermes adapter closer to feature parity with the claude-local adapter, addressing multiple open issues and incorporating fixes from several community PRs. ## Fixes included ### Read wake context from ctx.context, not ctx.config (NousResearch#17, NousResearch#26) Task ID, comment ID, wake reason, and other wake fields are now read from ctx.context (the Paperclip wake payload) with fallback to ctx.config for backward compatibility. Previously these were read from ctx.config which only contains adapter configuration, not wake context. ### Inject PAPERCLIP_API_KEY from ctx.authToken (NousResearch#2, NousResearch#4, NousResearch#5) The auth token is now injected into the child process environment as PAPERCLIP_API_KEY. All curl examples in the default prompt template include Authorization and X-Paperclip-Run-Id headers. Without this, agent API calls were unauthenticated and comments were attributed to the Board instead of the agent. ### Add auth headers to all curl commands in prompt template (NousResearch#5, NousResearch#7) Every curl example now includes -H "Authorization: Bearer $PAPERCLIP_API_KEY" and mutating requests include -H "X-Paperclip-Run-Id: $PAPERCLIP_RUN_ID" for proper attribution. ### Inject AGENTS.md instructions into prompt (NousResearch#1, NousResearch#14-related) Reads instructionsFilePath from adapter config and prepends the file content to the prompt. This mirrors claude-local's --append-system-prompt-file behavior. Previously, content written in the Paperclip Instructions tab was stored on disk but never passed to the Hermes process. ### Forward onSpawn callback to runChildProcess (NousResearch#23) Passes ctx.onSpawn through to runChildProcess so Paperclip can record the child process PID. Without this, runs showed processPid=null and could be incorrectly reaped as process_lost. ### Emit onMeta invocation metadata (NousResearch#14-related) Calls ctx.onMeta before spawning the process with adapter type, command, args, cwd, redacted env, and prompt content. This allows Paperclip to display execution metadata in the run detail view. ### Fall back to config.command when hermesCommand is missing (NousResearch#24, NousResearch#25) The UI writes the binary path as "command" but the adapter only read "hermesCommand". Now falls back to config.command before the default. ### Unwrap legacy secret-ref env var format (NousResearch#27, NousResearch#29) Handles the legacy wrapped env var format ({ type: "plain", value: "..." }) that older Paperclip versions may pass. The server should resolve these before calling execute(), but this adds defense-in-depth. ### Pass workspace context as environment variables Sets PAPERCLIP_WORKSPACE_CWD, PAPERCLIP_WORKSPACE_SOURCE, PAPERCLIP_WORKSPACE_STRATEGY, PAPERCLIP_WORKSPACE_ID, PAPERCLIP_WORKSPACE_REPO_URL, PAPERCLIP_WORKSPACE_REPO_REF, PAPERCLIP_WORKSPACE_BRANCH, PAPERCLIP_WORKSPACE_WORKTREE_PATH, and AGENT_HOME from ctx.context.paperclipWorkspace. ### Pass additional wake context as environment variables Sets PAPERCLIP_WAKE_REASON, PAPERCLIP_WAKE_COMMENT_ID, PAPERCLIP_LINKED_ISSUE_IDS, and PAPERCLIP_WAKE_PAYLOAD_JSON. ### Use workspace CWD from Paperclip context Prefers ctx.context.paperclipWorkspace.cwd over config.cwd when workspace isolation is enabled (source !== "agent_home"). ### Structured wake prompt via renderPaperclipWakePrompt When available in adapter-utils, uses the standard Paperclip wake prompt renderer for structured wake payloads. Falls back gracefully on older adapter-utils versions. ### Session handoff markdown injection Includes ctx.context.paperclipSessionHandoffMarkdown in the prompt when the server rotates sessions. ### Composable prompt construction via joinPromptSections Prompt is now assembled from discrete sections (instructions, wake prompt, session handoff, heartbeat template) using joinPromptSections, matching the claude-local approach. ### Include CWD in session params Session params now include cwd alongside sessionId, matching claude-local's session codec contract. ### Full session display ID sessionDisplayId now returns the full session ID instead of truncating to 16 characters. ### Proper timeout error reporting Timed-out runs now set errorMessage and errorCode: "timeout" on the result, matching other adapters. ### Remove unnecessary (ctx as any) casts ctx.context and ctx.authToken are first-class fields on AdapterExecutionContext — the type casts were unnecessary. ## Backward compatibility All new features degrade gracefully: - adapter-utils functions that may not exist in older versions are dynamically imported with fallback - Wake context fields fall back to ctx.config for older server versions - Legacy env var wrapping is handled alongside plain strings Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
11 tasks
kit-floating
pushed a commit
to kit-floating/hermes-paperclip-adapter
that referenced
this pull request
Apr 6, 2026
Brings the Hermes adapter to near-complete feature parity with the claude-local and codex-local reference adapters, addressing 6 open issues and incorporating fixes from 7 community PRs. ## Issues addressed - NousResearch#2 — Missing PAPERCLIP_API_KEY injection - NousResearch#5 — Inject auth token and add auth headers to curl workflow - NousResearch#13 — Can't get assigned issues (ctx.context vs ctx.config) - NousResearch#14 — Emit transcript/invocation events (onMeta) - NousResearch#24 — execute.ts ignores adapterConfig.command - NousResearch#27 — HERMES_HOME env var passed as [object Object] ## Community PRs incorporated - NousResearch#1 (@fa1k3) — AGENTS.md injection - NousResearch#4 (@shivasymbl) — Inject PAPERCLIP_API_KEY from ctx.authToken - NousResearch#17 (@optomachina) — Read wake context from ctx.context - NousResearch#23 (@lucasproko) — Forward onSpawn callback - NousResearch#25 (@ScaleLeanChris) — Fall back to config.command - NousResearch#26 (@mattverlaque) — ctx.context + authToken + prompt auth - NousResearch#29 (@AnandDN) — Unwrap secret-ref env vars ## Changes ### Prompt template alignment - Replace 60-line hardcoded DEFAULT_PROMPT_TEMPLATE with the standard one-liner used by all other Paperclip adapters. The heartbeat workflow, curl examples, and API reference are provided by the paperclip skill, not hardcoded into the adapter. - Add bootstrapPromptTemplate support (first-run only prompt, omitted on session resume to reduce token waste). - Compose prompt via joinPromptSections: instructions + bootstrap + wake + session handoff + heartbeat template. - Inject sessionHandoffMarkdown on session rotation. ### Skills injection - Read skill entries from config.paperclipRuntimeSkills (provided by the Paperclip server), symlink into temp dir, pass via -s flag. Replaces the need for manual external_dirs in Hermes profile config. - Clean up temp skills directory in finally block. ### Instructions tab (AGENTS.md) - Read config.instructionsFilePath and prepend content to prompt. Mirrors claude-local's --append-system-prompt-file behavior. Previously, Instructions tab content was stored but never passed to the Hermes process. ### Auth and attribution - Inject ctx.authToken as PAPERCLIP_API_KEY (guarded: only set if config.env doesn't already contain an explicit PAPERCLIP_API_KEY). - Fall back to config.command when hermesCommand is missing. - Unwrap legacy { type: "plain", value: "..." } env var format. ### Wake context - Read task/comment/wake fields from ctx.context (wake payload) with fallback to ctx.config for backward compatibility. - Set all PAPERCLIP_* env vars matching claude-local: RUN_ID, TASK_ID, WAKE_REASON, WAKE_COMMENT_ID, APPROVAL_ID, APPROVAL_STATUS, LINKED_ISSUE_IDS, WAKE_PAYLOAD_JSON, all WORKSPACE_* vars, AGENT_HOME, WORKSPACES_JSON, RUNTIME_SERVICE_INTENTS_JSON, RUNTIME_SERVICES_JSON, RUNTIME_PRIMARY_URL. - Use renderPaperclipWakePrompt for structured wake payloads. - Use workspace CWD from context when workspace isolation is enabled. ### Execution metadata - Call ctx.onMeta with adapterType, command, cwd, args, redacted env, prompt, and context. - Forward ctx.onSpawn to runChildProcess for PID tracking. - Validate hermes binary via ensureCommandResolvable before spawning. - Create workspace directory if missing (ensureAbsoluteDirectory with createIfMissing). ### Session management - Validate session CWD before resume — start fresh if CWD changed. - Retry with fresh session on unknown session error instead of failing. - Set clearSession on session retry or max-turns detection. - Enrich sessionCodec with cwd, workspaceId, repoUrl, repoRef fields (matching claude-local/codex-local). ### Result object - Add biller and billingType fields (inferred from resolved provider). - Set errorCode: "timeout" on timed-out runs. - Return full sessionDisplayId instead of truncating to 16 chars. ### Output parsing - Extract parse.ts module from execute.ts with exported functions: parseHermesOutput, cleanResponse, isHermesUnknownSessionError, isHermesMaxTurnsResult. - Re-export parse functions from server/index.ts. ### UI build-config - Add instructionsFilePath, bootstrapPromptTemplate, env bindings (plain + secret_ref), provider, and toolsets to buildHermesConfig. - Add parseEnvVars and parseEnvBindings helpers. ### Environment test - Add CWD validation check. - Add live hello probe (hermes chat -q "Respond with hello" -Q, 45s timeout) with profile arg forwarding. ### Documentation - Update agentConfigurationDoc with new config fields. ### Tests - Add 31 unit tests for parse module using node:test runner. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
encountered these issues myself and patched locally, good to see there's an open PR for it. Merge it! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The Hermes adapter has several bugs that prevent it from functioning correctly as a Paperclip agent:
buildPrompt()readsctx.configinstead ofctx.contextfor task/comment data.ctx.configonly contains adapterConfig (model, provider, timeout). The wake context (taskId, commentId, wakeReason) lives inctx.context. This means every run hits the{{#noTask}}heartbeat path — the agent never knows it was woken for a specific task or comment. The@paperclipai/adapter-claude-localcorrectly reads fromcontext.taskIdetc.Environment vars section has the same
ctx.configbug.PAPERCLIP_TASK_IDis never set. Also missingPAPERCLIP_WAKE_REASONandPAPERCLIP_WAKE_COMMENT_ID.ctx.authTokenis never injected asPAPERCLIP_API_KEY. Paperclip generates a JWT for each agent and passes it viactx.authToken. The Claude adapter sets this asPAPERCLIP_API_KEYin the child env. The Hermes adapter ignores it, so all API calls are unauthenticated and comments are attributed to the board user instead of the agent.Quiet mode defaults to
true, stripping structured output. Theparse-stdout.jsUI parser needs the┊-prefixed tool lines that-Qsuppresses. With quiet mode on, Paperclip renders everything as system messages instead of tool cards.Prompt template curl commands have no auth headers. Even with the env var fixed, the prompt examples don't include
-H "Authorization: Bearer $PAPERCLIP_API_KEY". Also addsX-Paperclip-Run-Idto mutations, checkout step, and removes python3 one-liners that cause shell escaping issues.How it was found
Compared line-by-line against
@paperclipai/adapter-claude-local/dist/server/execute.jswhich handles the sameAdapterExecutionContextcorrectly.Changes
src/server/execute.ts: All 5 fixes above (38 insertions, 21 deletions)