OAF-031 context handoff readiness#8
Conversation
…ntake-harness-bridge # Conflicts: # PROJECT_STATUS.json # README.md # REPOSITORY_MANIFEST.json # THIRD_PARTY.md # apps/cli/oaf.mjs # docs/architecture/native-providers.md # docs/product/loop-workbench-build-plan.md # docs/product/loop-workbench.md # docs/release/1.0-PROVENANCE.json # docs/release/1.0-READINESS-REPORT.md # docs/release/1.0-REPRODUCIBILITY.md # docs/superpowers/plans/2026-06-26-native-core-handoff.md # docs/superpowers/plans/2026-06-30-rust-super-banger-hardening.md # packages/context-compiler/src/index.mjs # packages/harness-context/src/index.mjs # services/control-api/src/route-contracts.mjs # tests/cli.test.mjs
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 55c60ef7f3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| name: server, | ||
| transport: 'stdio', | ||
| command: 'npm', | ||
| command: 'oaf', |
There was a problem hiding this comment.
Use a runnable MCP server command in setup plans
When users run OAF from a normal source checkout, the documented entry point is npm run oaf -- ... and the package is still private, so there is no guarantee that a bare oaf binary is on the PATH. The harness setup plan now emits MCP client config with command: 'oaf', which makes Codex/Cursor/Claude fail to spawn the read-only bridge with ENOENT unless the user has separately installed or linked the package; this regresses the local checkout flow that the surrounding generated commands still use. Please keep the setup config runnable from the checkout, e.g. the previous npm wrapper or an absolute Node/CLI path like mcp install uses.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ba49d6eab2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| export const CONTEXT_VIEW_ALGORITHM = 'oaf_context_view_v1'; | ||
| const CONTEXT_VIEW_KINDS = new Set(['auto', 'json', 'log', 'code', 'markdown', 'text']); | ||
| const CONTEXT_VIEW_SECRET = /\b(?:token|secret|password|authorization|api[_-]?key|database_url|db_url|connection_string)\s*[:=]\s*[^\s,;]+/giu; | ||
| const CONTEXT_VIEW_LOCAL_PATH = /(?:\/Users\/[^\s'")]+|\/private\/[^\s'")]+|\/var\/folders\/[^\s'")]+|[A-Za-z]:\\[^\s'")]+)/gu; |
There was a problem hiding this comment.
Treat Linux home paths as private in context views
When a record enables metadata.contextView on a Linux workspace, this redaction regex leaves paths such as /home/alice/project/private.txt unchanged; createContextView() then compacts and returns that path in the selected context text, which can be persisted or sent onward as model context. Other private-material guards in the repo treat /home/... as unsafe, so the context-view redactor should cover the same absolute-path set before compacting.
Useful? React with 👍 / 👎.
| const MCP_STDIO_MAX_STDIN_BYTES = boundedEnvInteger('OAF_MCP_STDIO_MAX_STDIN_BYTES', 64 * 1024, { min: 1, max: 512 * 1024 }); | ||
| const MCP_STDIO_MAX_LINE_BYTES = boundedEnvInteger('OAF_MCP_STDIO_MAX_LINE_BYTES', 32 * 1024, { min: 1, max: 512 * 1024 }); | ||
| const MCP_STDIO_MAX_MESSAGES = boundedEnvInteger('OAF_MCP_STDIO_MAX_MESSAGES', 16, { min: 1, max: 64 }); | ||
| const MCP_STDIO_CHILD_TIMEOUT_MS = boundedEnvInteger('OAF_MCP_STDIO_CHILD_TIMEOUT_MS', 30_000, { min: 1, max: 60_000 }); | ||
| const MCP_STDIO_CHILD_MAX_STDOUT_BYTES = boundedEnvInteger('OAF_MCP_STDIO_CHILD_MAX_STDOUT_BYTES', 512 * 1024, { min: 1, max: 2_000_000 }); | ||
| const MCP_STDIO_CHILD_MAX_STDERR_BYTES = boundedEnvInteger('OAF_MCP_STDIO_CHILD_MAX_STDERR_BYTES', 64 * 1024, { min: 1, max: 512 * 1024 }); | ||
| const SECRET_LIKE = /\b(?:authorization\s*[:=]\s*(?:"[^"\r\n]*"|'[^'\r\n]*'|(?:Bearer|Basic|Digest|Token)\s+[^\s"'`,;)]+|[^\s"'`,;)]+)|(?:api[_-]?key|token|secret|password)\s*[:=]\s*(?:"[^"\r\n]*"|'[^'\r\n]*'|[^\s"'`,;)]+))/iu; | ||
| const PRIVATE_LOCAL_PATH = /(?:^|[\s"'`(])(?:\/Users|\/private|\/var\/folders)(?:\/|$)/u; |
There was a problem hiding this comment.
Withhold retrieved content containing Linux paths
When oaf context retrieve ... --format json reads a workspace file containing a Linux home path like /home/alice/private.txt (or a Windows absolute path), this pattern does not mark the file sensitive, so the new retrieve path reports state: "ready" and includes the raw content. The command is intended to withhold absolute local paths, and nearby MCP private-material patterns already include /home and Windows drive paths, so this predicate should be brought in line before deciding contentIncluded.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
https://github.com/rebel0789/open-agent-fabric/blob/4208f72b773c47d88e5c98824f7de3a0d5674c90/apps/cli/oaf.mjs#L5976-L5977
Escape Windows paths in generated TOML configs
On Windows, or any install path containing backslashes, the Codex TOML config written by mcp install --client codex --apply is invalid because the writer interpolates serverConfig.command directly and the args escape only quotes; paths like C:\Program Files\nodejs\node.exe contain invalid TOML escapes such as \P. The install can report success while Codex cannot parse or spawn the server, so the TOML writer should escape backslashes or use TOML literal strings.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| process.exitCode = 2; | ||
| return; | ||
| } | ||
| const target = option(values, '--locator') ?? option(values, '--hash') ?? firstPositional(values); |
There was a problem hiding this comment.
Parse retrieve positionals after boolean flags
When the new retrieve form is invoked with the required flag before the locator, e.g. oaf context retrieve --read-only workspace://README.md, firstPositional() treats the locator as the value of --read-only and skips it, so target is null (or becomes json when --format json is also present). This makes the documented flag-first CLI shape fail unless users know to pass --locator or put the locator before all flags; parse positionals with known value flags or require the explicit locator/hash option here.
Useful? React with 👍 / 👎.
| const skillDocument = await stat(skillDocumentPath).catch((error) => { | ||
| if (error.code === 'ENOENT') return null; | ||
| throw error; | ||
| }); | ||
| if (!skillDocument?.isFile()) throw new Error(`${relativeDirectory}/SKILL.md is missing`); |
There was a problem hiding this comment.
Reject symlinked skill files before load plans
When a skill's SKILL.md is a symlink to a file outside the workspace, stat() follows it and isFile() passes, so skill load-plan emits workspace://skills/.../SKILL.md as a required read even though following that path escapes the workspace; the reference checks below use the same follow-symlink pattern. Use lstat plus realpath/inside-root validation before marking skill docs/references present.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 01100fc34a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const mcp = await applyMcpConfig({ action, home, setup, generatedAt }); | ||
| const hooks = await applyHookConfig({ action, home, setup, generatedAt }); |
There was a problem hiding this comment.
Validate hook config before writing MCP config
When oaf connect codex --yes runs against a home directory whose hook file is malformed, such as an invalid .codex/hooks.json, this writes the MCP config before applyHookConfig() parses and throws on the hook file. The command exits with an error and no receipt, but the home MCP config has already been changed, leaving a partial connection; preflight both target configs or roll back the first write before reporting failure.
Useful? React with 👍 / 👎.
| return; | ||
| } | ||
| try { | ||
| const agent = normalizeConnectionAgent(option(values, '--agent') ?? option(values, '--client') ?? firstPositional(values) ?? 'codex'); |
There was a problem hiding this comment.
Preserve the requested agent after boolean flags
When the agent is supplied positionally after a boolean flag, for example oaf connect --yes claude-code --home ..., firstPositional(values) skips claude-code because it treats every flag as if it had a value, so this expression falls back to codex. With --yes this writes or removes Codex config instead of the requested Claude config; parse connect positionals with the known value flags or require --agent.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
https://github.com/rebel0789/open-agent-fabric/blob/8e3443f92259b88aced3bfd34e6ca9799f0500fb/apps/cli/oaf.mjs#L5976-L5977
Escape Windows paths in TOML install output
When oaf mcp install --client codex is run on Windows, desiredServer.command and the absolute args come from process.execPath, CLI_PATH, and workspace paths, so they contain backslashes. This TOML writer only escapes quotes, which makes paths such as C:\Program Files\nodejs\node.exe contain invalid or unintended TOML escape sequences, leaving Codex with an unparsable or wrong MCP command; escape backslashes too or emit TOML literal strings.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const reviewedToolIds = new Set(toolReview.state === 'ready' ? toolReview.reviewedToolIds : []); | ||
| const unreviewedToolIds = skill.tools.filter((toolId) => !reviewedToolIds.has(toolId)); |
There was a problem hiding this comment.
Block skills that depend on disabled tools
When a tool catalog entry is reviewed but disabled (enabled: false, reviewStatus: "reviewed") and a skill declares that tool, this readiness check still treats the tool as available because it only consults reviewedToolIds; buildSkillCatalogToolReview() separately reports disabledReviewedToolIds, but that list is ignored here. In that scenario the skill catalog/load-plan can mark a read-only skill ready even though its required tool cannot be invoked, so use enabledReviewedToolIds for readiness or explicitly block disabled reviewed tools.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b1fa39e389
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| import { spawnSync } from 'node:child_process'; | ||
|
|
||
| export function timedSpawn(command, args, options = {}) { | ||
| const timeArgs = process.platform === 'darwin' ? ['-l'] : ['-v']; |
There was a problem hiding this comment.
Fall back when
/usr/bin/time is unavailable
On minimal Linux/local environments where /usr/bin/time is not installed (including the review container), timedSpawn(process.execPath, ['--version']) returns ENOENT, and the Rust quality scripts that now import this helper assert result.status === 0, so commands such as rust-eval fail before running the actual binary. Use PATH discovery or fall back to spawning the command directly when the timing tool is unavailable.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: caf0f1ca7a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (/(^|\/)(?:\.git|\.local|node_modules)(?:\/|$)/u.test(relativePath)) throw new Error(`${label} points to an unsupported workspace location`); | ||
| return relativePath; | ||
| } | ||
|
|
||
| function memoryProposalCommand(configPath = 'oaf.memory.json') { | ||
| return `npm --silent run oaf -- memory proposals --from memoryPaths --config ${shellQuote(configPath)} --root . --dry-run --format json`; | ||
| return `oaf memory proposals --from memoryPaths --config ${shellQuote(configPath)} --root . --dry-run --format json`; |
There was a problem hiding this comment.
Keep memory preflight commands runnable from checkouts
When context handoff --memory-config ... is run from a normal source checkout, the generated memoryProposalPreflight.command now tells recipients to execute a bare oaf ... command. This repo is private and the local checkout entry point is the npm wrapper, so users who ran the handoff via npm run oaf -- ... can get command not found before reviewing the proposed memory sources. Use the checkout wrapper or an absolute Node/CLI path for this generated preflight command.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 358bc73607
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| previewSetup: `oaf harness setup plan --client ${setupClient} --server oaf --dry-run --format json`, | ||
| startMcpBridge, | ||
| readCurrentContextPack: `npm --silent run oaf -- mcp resources --read-only --context-pack ${baseCommand} --uri oaf://workspace/${workspaceId}/context-pack/current --format json`, | ||
| renderMarkdown: `npm --silent run oaf -- context pack ${baseCommand} --dry-run --format markdown` | ||
| readCurrentContextPack: `oaf mcp resources --read-only --context-pack ${baseCommand} --uri oaf://workspace/${workspaceId}/context-pack/current --format json`, | ||
| renderMarkdown: `oaf context pack ${baseCommand} --dry-run --format markdown`, | ||
| refineMemory: 'oaf memory refine --read-only --root . --sqlite .local/memory.sqlite --target-active-facts 200 --format json', |
There was a problem hiding this comment.
Keep handoff follow-up commands checkout-runnable
Fresh evidence beyond the earlier setup/memory surfaces: the main context handoff --read-only report now emits its follow-up commands with a bare oaf binary. In a normal source checkout this repo documents npm run oaf -- ..., and the package is private, so recipients who have not globally installed or linked oaf hit command not found before they can preview setup, read the MCP resource, render markdown, or refine memory from the handoff.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 31ce0f0830
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| export const OAF_MCP_TOKEN_SAVER_ARGS = Object.freeze(['--silent', 'run', 'oaf', '--', 'mcp', 'server', '--read-only', '--root', '.', '--stdio']); | ||
| export const OAF_MCP_RESOURCE_BINARY_ARGS = Object.freeze(['mcp', 'resources', '--read-only', '--stdio']); | ||
| export const OAF_MCP_TOKEN_SAVER_BINARY_ARGS = Object.freeze(['mcp', 'server', '--read-only', '--root', '.', '--stdio']); | ||
| const OAF_HOOK_CONTEXT_COMMAND = 'oaf hook context --read-only --format text'; |
There was a problem hiding this comment.
Use a checkout-runnable hook command
Fresh evidence beyond the earlier bare-oaf command surfaces: when connect --yes or the hook setup snippet installs this command from a normal source checkout, the hook runs in Codex/Claude with oaf hook context ... even though this private repo’s runnable entry point is npm run oaf -- .... Unless the user separately linked or globally installed the package, every configured SessionStart/UserPromptSubmit/PreCompact hook fails with ENOENT, so emit the npm wrapper or an absolute CLI path here before writing hook configs.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
https://github.com/rebel0789/open-agent-fabric/blob/595c037582a7a846b412a2a57d47d812a9a179d7/apps/cli/oaf.mjs#L5388-L5389
Do not apply MCP cursors across different queries
When a client first calls memory.recall/context.profile for one query and then calls the same tool for a different query without since, the persisted cursor is still found because this key only uses workspaceId, toolName, client, and scope. The handler then injects that since value and returns only records changed after the prior call; with the server timestamp cursor this makes existing facts for the second query disappear. Include the query/objective/filter fields in the cursor key or only use persisted cursors when the caller explicitly asks for a delta.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const statsRecorder = await createMcpStatsRecorder({ values, root, workspaceId, generatedAt: fixedNow() }); | ||
| const cursorStore = await createMcpCursorStore({ values, root, workspaceId }); | ||
| const tools = buildMcpTokenSaverTools({ values, root, workspaceId, generatedAt: fixedNow(), statsRecorder, cursorStore }); | ||
| await mcpResourcesStdio({ |
There was a problem hiding this comment.
Process MCP stdio messages before EOF
When the new token-saver server is launched by the generated MCP config, real clients keep stdin open after sending initialize. This path calls mcpResourcesStdio(), which waits for readStdinText() to finish before bridge.handle() runs, so no initialize response is emitted until the client closes the pipe; a normal MCP client will hang during startup. Handle newline-delimited JSON-RPC messages as they arrive for this server mode.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 877cf09860
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| request.step, | ||
| ...(request.requiredEntities ?? []) | ||
| ].filter(Boolean).join(' '); | ||
| const graphKey = stableStringify({ workspaceRoot, workspaceId: request.workspaceId ?? workspaceId, maxFileBytes, maxFiles }); |
There was a problem hiding this comment.
Invalidate source graph cache after workspace edits
When the same createNativeSourceGraphCandidateSource instance is reused after a JS/TS file changes (for example in a long-lived server or eval process serving multiple context requests), this cache key only includes the root, workspace id, and limits, so cachedGraph is reused even though the file graph has changed. That makes later queries return stale locators or miss newly added symbols until the process restarts; include a content/mtime fingerprint in the key or avoid caching across queries.
Useful? React with 👍 / 👎.
Summary
Verification
Review Queue Note