Repository navigation
AGENTS.md still loaded twice when launched from $HOME in 1.82.5 (follow-up to #730) #1034
Description
Summary
When the working directory is $HOME and only $HOME/.commandcode/AGENTS.md exists, one file is emitted twice in the system prompt. The same single file receives two # Memory from: blocks, repeating the user instructions and consuming additional prompt context.
This is a follow-up to #730, which was closed as completed on 2026-08-29. The latest npm release still reproduces the reported render-time failure. The earlier fix may not have reached the published package; this report does not establish that a previously working published release regressed.
Steps to reproduce the issue
The following macOS/Node reproduction executes the published bundle's loadAllMemories and getMemoryContent functions verbatim, with a minimal filesystem/runtime adapter. It creates a disposable home containing only a synthetic marker, excludes enterprise memory, and compares the home cwd with an empty control cwd. It does not start the CLI, require a login, or read the real home directory. Run in a disposable working directory:
work=$(mktemp -d /tmp/command-code-memory.XXXXXX)
cd "$work"
npm pack command-code@1.82.5 >/dev/null
tar -xzf command-code-1.82.5.tgz
node --input-type=module <<'JS'
import fs from 'node:fs/promises';
import path from 'node:path';
import vm from 'node:vm';
import assert from 'node:assert/strict';
const source = await fs.readFile('package/dist/cli.mjs', 'utf8');
const start = source.indexOf('function toPosix2(');
const end = source.indexOf('async function mentionedContextPaths(', start);
assert(start >= 0 && end > start);
const sandbox = vm.createContext({
__name: fn => fn, cb: 'AGENTS.md', lb: '.commandcode', ab: 5,
ib: /^(?:[a-zA-Z]:[\\/]|\\\\)/,
});
vm.runInContext(source.slice(start, end), sandbox);
const fixture = await fs.mkdtemp(path.join(process.cwd(), 'fixture-'));
const home = path.join(fixture, 'home');
const control = path.join(fixture, 'empty-control');
await fs.mkdir(path.join(home, '.commandcode'), {recursive: true});
await fs.mkdir(control);
await fs.writeFile(path.join(home, '.commandcode', 'AGENTS.md'), 'CC_MEMORY_DUPLICATION_MARKER\n');
const runtime = {
env: () => ({HOME: home}), platform: () => 'darwin',
fs: {
exists: async ({path: p}) => p.startsWith(fixture + '/') && fs.access(p).then(() => true, () => false),
stat: async ({path: p}) => ({isFile: (await fs.stat(p)).isFile()}),
read: ({path: p}) => fs.readFile(p, 'utf8'),
},
};
for (const [label, cwd] of [['home', home], ['empty control', control]]) {
const memories = await sandbox.loadAllMemories({runtime, cwd});
const content = await sandbox.getMemoryContent({runtime, cwd});
const result = {cwd: label, uniqueFiles: memories.size,
headers: (content.match(/^# Memory from:/gm) || []).length,
markers: (content.match(/CC_MEMORY_DUPLICATION_MARKER/g) || []).length};
console.log(JSON.stringify(result));
assert.equal(result.uniqueFiles, 1);
assert.equal(result.headers, label === 'home' ? 2 : 1);
assert.equal(result.markers, result.headers);
}
await fs.rm(fixture, {recursive: true});
JS
cd /
rm -rf "$work"User-facing trigger: launch cmd with cwd equal to $HOME, with $HOME/.commandcode/AGENTS.md present and $HOME/AGENTS.md absent. The helper reproduction above exercises the memory path used by createSystemPromptBuilder, which calls getMemoryContent with runtime.cwd().
Expected Behavior
Emit one block per distinct memory source path: the fixture must produce one header and one marker in both cwd cases. When user and project candidates resolve to the same path, their overlap should not duplicate its content.
Actual Behavior
The direct-function reproduction exits successfully with:
{"cwd":"home","uniqueFiles":1,"headers":2,"markers":2}
{"cwd":"empty control","uniqueFiles":1,"headers":1,"markers":1}The loader returns one unique file in both cases, but the renderer emits two copies when cwd equals the fixture home. Separately, the reporter observed the same two-header result in an interactive macOS session launched from home and one header from an empty directory. That interactive observation is supplied evidence; this rerun directly verified the bundle functions.
Evidence
- Expected source: The bundled
dist/bundled/command-code-knowledge/reference/memory.mddocuments user and project memory sources; the maintainer diagnosis on the prior report explicitly confirms that a source shared by tiers should be injected once. - Failure source: The inline reproduction and JSON output above execute the published
dist/cli.mjsmemory functions using one synthetic file and an empty-directory control. - Evidence provenance: observed
- Local verification: reproduced
- Reproduction completeness: complete
The published code stores loaded memories in a path-keyed Map. getMemoryContent then emits the user block and the first existing project candidate independently. When those paths are equal, both emissions use the same entry:
r.has(a)&&c(a),r.has(i)&&c(i);
for(const e of l)if(r.has(e)){c(e);break}Here i is the user-memory path and l contains the project-memory candidates. This matches the earlier maintainer diagnosis. No claim is made about the current private fix or its merge/release status.
Restoration check
With the same one-file fixture, the home cwd must change from two headers/two markers to one header/one marker, while the empty control remains at one header/one marker. User memory must remain present in both cases. Distinct user and project files must still each contribute their own block; suppressing project memory generally would not restore the contract.
Command Code Version
1.82.5 (command-code@latest at verification; installed cmd --version --no-auto-update agrees).
Downloaded tarball SHA-1: a6457830fcb0a2ae37ff5146a65dad814a10d007. Bundle dist/cli.mjs SHA-256: c6169b37e3301f146455207b61192454dc0da2790e958599e1789ec37ad0cf88.
Operating System
macOS
Measured environment: macOS 27.0.1 arm64; Node v26.10.0.
Terminal/IDE
Terminal with tmux for the supplied interactive observation; not required for the direct-function reproduction.
Shell
zsh 5.9
Triage assessment
- Impact level: P2
- Assessment status: supported
- Impact basis: The home-directory launch repeats user instructions and their prompt-context payload; the direct reproduction observes two rendered blocks for one source. No downstream model-behavior failure or token-billing amount was measured.
- Workaround status: available
- Workaround basis: Launching from an empty directory retains the user memory exactly once in the verified control. This avoids duplication when changing the working directory is acceptable; it does not restore the home-directory workflow.
Activity
vipulgupta2048 commentedon Oct 21, 2026
Thanks for reporting this, check this issue right now @coygeek
coygeek commentedon Oct 21, 2026
Thanks @vipulgupta2048! Quick update: this still reproduces on 1.86.2 (current
latest).getMemoryContentstill pushes the user-memory block and the first existing project candidate separately:With cwd =
$HOME,i(~/.commandcode/AGENTS.md) is also the second project candidate, so the same file is emitted twice.The repro from the issue body still works against 1.86.2. Only the minified constant names changed (
cb/lb/ab/ib→yT/fT/gT/hT):Output on 1.86.2:
{"cwd":"home","uniqueFiles":1,"headers":2,"markers":2} {"cwd":"empty control","uniqueFiles":1,"headers":1,"markers":1}dist/cli.mjsSHA-256:ea199ce2a2292eaffa23185050e5dd14394fd1b07af69e561740ccfeeed3700f(matches my installed copy).Also confirmed it's not specific to my machine: on a fresh Ubuntu 26.04 container (Node 24.22.0, clean
npm i -g command-code@1.86.2, samecli.mjshash), both the function-level repro above and an end-to-end run of the real CLI show the duplication. For the end-to-end check I rancmd -p --local-onlyagainst a keyless BYOK provider pointing at a local recorder and counted blocks in the captured system prompt: cwd =$HOME→ 2# Memory from:headers / 2 markers; cwd = empty dir → 1 / 1.Possible fix: in
getMemoryContent, track emitted paths in aSetand skip any project candidate already emitted (or just skipe === i). Distinct user and project files would still each get their own block.vipulgupta2048 commentedon Oct 21, 2026
Thanks for responding back, just merged a fix for this @coygeek and should be shipping out in the latest release