Skip to content

Move trajectory storage under .agentworkforce#28

Merged
willwashburn merged 2 commits into
mainfrom
codex/move-agentworkforce-trajectories
May 26, 2026
Merged

Move trajectory storage under .agentworkforce#28
willwashburn merged 2 commits into
mainfrom
codex/move-agentworkforce-trajectories

Conversation

@willwashburn
Copy link
Copy Markdown
Member

Summary

  • change the default trajectory data directory to .agentworkforce/trajectories
  • migrate existing legacy .trajectories data on initialization when the new default is absent
  • update CLI, SDK docs, tests, viewer path resolution, workflows, and tracked trajectory artifacts for the new path

Verification

  • npm run typecheck
  • npm run build
  • ./node_modules/.bin/biome check src tests scripts workflows trail-viewer/server/src biome.json
  • npm run test:run

Note: a broader Biome check including package.json reports pre-existing package.json formatting on main; package metadata is not changed in this PR.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR migrates the default trajectory storage location from .trajectories/ to .agentworkforce/trajectories/ across the entire codebase. The core storage layer now provides default path constants and a legacy directory migration helper. All CLI commands, the trail viewer app, tests, documentation, and workflow definitions are updated to use the new path.

Changes

Storage directory migration and default path management

Layer / File(s) Summary
Storage layer defaults and migration logic
src/storage/file.ts, src/storage/index.ts, src/index.ts
DEFAULT_TRAJECTORY_DATA_DIR, LEGACY_TRAJECTORY_DATA_DIR, and getDefaultTrajectoryDataDir(baseDir) are introduced to compute and export the new default directory. getSearchPaths() now falls back to .agentworkforce/trajectories when no env vars are set. FileStorage initialization calls migrateLegacyDefaultDir() to rename legacy .trajectories directories into the new location.
CLI commands and config using new default paths
src/cli/commands/compact.ts, src/cli/commands/complete.ts, src/cli/commands/export.ts, src/compact/config.ts
compact, complete, and export commands import and use getDefaultTrajectoryDataDir() instead of hardcoding .trajectories as the output/working directory fallback. The compaction config module uses the same helper for its primary config directory.
User-facing CLI paths and documentation
src/cli/commands/doctor.ts, src/core/trailers.ts, src/sdk/client.ts
User-visible messages in doctor command, git hook script templates, and SDK JSDoc now reference .agentworkforce/trajectories/ for quarantine and storage locations.
Trail viewer app path resolution
trail-viewer/Sources/AppConfiguration.swift, trail-viewer/Sources/Services/LocalServerManager.swift, trail-viewer/Sources/Services/SpotlightRegistration.swift, trail-viewer/Sources/Services/QuickLookGenerator.swift, trail-viewer/Sources/Views/WelcomeView.swift, trail-viewer/server/src/trajectory-service.ts
The Swift trail-viewer app defaults and resolution logic are updated to detect and handle .agentworkforce/trajectories/ while maintaining fallback support for legacy .trajectories layout. The Node.js trajectory service backend adds helpers to resolve trajectory data directories correctly.
Build configuration and repository tooling
.gitignore, biome.json, package.json
.gitignore excludes the new .agentworkforce/trajectories/active/ directory. biome.json adds .agentworkforce to the formatter ignore list. package.json files array is reformatted.
Design documents and architecture guides
AGENTS.md, IMPLEMENTATION-PROPOSAL.md, PROPOSAL-trajectories.md, README.md, docs/architecture/core.md, docs/architecture/memory-integration.md, docs/architecture/web-viewer.md
All proposal, architecture, and user-facing documentation is updated to reference .agentworkforce/trajectories/ as the default storage location, including examples, diagrams, and workflow instructions.
Storage layer and filesystem behavior tests
tests/storage/storage.test.ts, tests/storage/concurrent-save.test.ts, tests/storage/reconcile-real-data.test.ts
Storage tests verify directory creation and migration under .agentworkforce/trajectories/, legacy .trajectories migration, index.json handling, environment variable behavior, and filesystem operations (save, delete, reconcile) with the new layout.
CLI, SDK, and compaction integration tests
tests/compact/llm-compact.test.ts, tests/export/export.test.ts, tests/sdk/workflow-compact.test.ts
Integration tests assert against the new .agentworkforce/trajectories/ structure for active, completed, compacted, and invalid trajectory locations across compaction, export, and SDK workflows.
Workflow task and benchmark definitions
scripts/benchmark-compaction.ts, workflows/compact-on-workflow-run.ts, workflows/llm-compaction.ts, workflows/sdk-autocompact-option.ts, workflows/sdk-workflow-autocompact.ts, workflows/fix-trajectory-schema/01-investigate.ts, workflows/fix-trajectory-schema/02-implement.ts, workflows/fix-trajectory-schema/README.md
Workflow tasks, embedded scripts, and benchmark fixtures are updated to expect artifacts under .agentworkforce/trajectories/compacted/, .agentworkforce/trajectories/completed/, and corresponding configuration paths.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • AgentWorkforce/trajectories#26: Introduces FileStorage.quarantineInvalid() and routes invalid files into .trajectories/invalid/; this PR builds on that by changing the default storage root and updating quarantine expectations to .agentworkforce/trajectories/invalid/.

Poem

🐰 The paths do shuffle, yet the files remain,
From .trajectories to .agentworkforce domain,
With legacy care and migration's grace,
Each trajectory finds its rightful place!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 19.23% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Move trajectory storage under .agentworkforce' directly and clearly describes the main change: relocating the default trajectory data directory from .trajectories to .agentworkforce/trajectories, which is the primary objective throughout the changeset.
Description check ✅ Passed The description is directly related to the changeset, outlining the three main objectives: changing the default directory, implementing migration logic, and updating documentation and tests to reflect the new path.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/move-agentworkforce-trajectories

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 139 files

Note: This PR contains a large number of files. cubic only reviews up to 100 files per PR, so some files may not have been reviewed. cubic prioritizes the most important files to review.
On a pro plan you can use ultrareview for larger PRs.

Re-trigger cubic

Comment thread trail-viewer/Sources/Services/LocalServerManager.swift Outdated
Comment thread workflows/fix-trajectory-schema/02-implement.ts
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a552c80c04

ℹ️ 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".

Comment thread src/storage/file.ts
}

return [join(process.cwd(), ".trajectories")];
return [getDefaultTrajectoryDataDir()];
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Include legacy data dir in default search fallback

getSearchPaths() now falls back only to .agentworkforce/trajectories, but trail compact code paths (loadTrajectories, getCompactedTrajectoryIds, discardSourceTrajectories) skip non-existent search paths before calling FileStorage.initialize(). In repos that still only have legacy .trajectories/, this means nothing is scanned and migration never runs, so compaction-related commands silently act as if there are no trajectories on first run after upgrade.

Useful? React with 👍 / 👎.

Comment on lines +141 to +144
if isDefaultDataDir || hasTrajectoryChildren {
resolvedTrajectoryPath = trajectoryPath
} else {
environment["TRAJECTORIES_DATA_DIR"] = trajectoryPath
resolvedTrajectoryPath = trajDirURL.path
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep legacy repo-root detection in viewer path resolver

When the viewer is pointed at a repository root that still uses .trajectories/, this logic rewrites TRAJECTORIES_DATA_DIR to <root>/.agentworkforce/trajectories unless the selected directory already looks like a data dir. A legacy repo root does not match those checks, so the server starts against a non-existent directory and existing trajectories disappear from the UI until users manually pick the legacy folder.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@PROPOSAL-trajectories.md`:
- Line 1139: Update the fenced code block showing the directory tree for
".agentworkforce/trajectories/" by adding a language identifier (e.g., ```text)
to the opening fence so Markdownlint MD040 is satisfied; locate the fenced block
that begins with the line ".agentworkforce/trajectories/" and change the opening
``` to include the language token (such as text) so the block becomes fenced
with ```text.

In `@trail-viewer/server/src/trajectory-service.ts`:
- Around line 92-94: The code builds trajDir by blindly appending
DEFAULT_TRAJECTORY_DATA_DIR to this.dataDir which double-nests when this.dataDir
already points to the trajectory directory; change the resolver to pick the base
dir = process.env.TRAJECTORIES_DATA_DIR ?? this.dataDir and then only append
DEFAULT_TRAJECTORY_DATA_DIR if the base's final path segment is not already
DEFAULT_TRAJECTORY_DATA_DIR (e.g. check path.basename(base) !==
DEFAULT_TRAJECTORY_DATA_DIR), then set trajDir = base or join(base,
DEFAULT_TRAJECTORY_DATA_DIR) and compute completedDir from trajDir; apply the
same change in rebuildIndex and getTrajectory to use the same resolution logic.
- Around line 19-33: The resolver currently only recognizes
DEFAULT_TRAJECTORY_DATA_DIR and will incorrectly redirect repo roots that still
use the legacy "./.trajectories" folder; update isTrajectoryDataDir and
resolveTrajectoryDataDir to treat the legacy name as a valid data dir. Modify
isTrajectoryDataDir to also detect the legacy folder (e.g., check
existsSync(join(path, ".trajectories")) or
normalized.endsWith(".trajectories")), and change resolveTrajectoryDataDir to
return the legacy path when that folder exists on the repo root (before falling
back to join(path, DEFAULT_TRAJECTORY_DATA_DIR)), using the existing function
names isTrajectoryDataDir and resolveTrajectoryDataDir for locating where to
apply the change.

In `@trail-viewer/Sources/Services/LocalServerManager.swift`:
- Around line 125-146: The code in LocalServerManager.swift determines
TRAJECTORIES_DATA_DIR using selected, trajDirURL, isDefaultDataDir,
hasActiveDir, hasCompletedDir and falls back to trajDirURL.path, but it doesn't
detect legacy repos that have a top-level ".trajectories" directory; add a check
for selected.appendingPathComponent(".trajectories", isDirectory: true) (e.g.,
let hasLegacyTrajectories = FileManager.default.fileExists(atPath:
selected.appendingPathComponent(".trajectories").path)) and incorporate it into
the resolution logic so that if hasLegacyTrajectories is true you set
resolvedTrajectoryPath to selected.appendingPathComponent(".trajectories").path
(preserving the existing behavior for isDefaultDataDir or hasTrajectoryChildren
otherwise) before assigning environment["TRAJECTORIES_DATA_DIR"].
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 106e2527-a0df-4d88-96bb-02bdb89fa665

📥 Commits

Reviewing files that changed from the base of the PR and between 1abd6e2 and eb59d68.

📒 Files selected for processing (140)
  • .agentworkforce/trajectories/active/trace_imxymv6f8x4b.json
  • .agentworkforce/trajectories/active/traj_1775656221707_fbafbb4c.json
  • .agentworkforce/trajectories/completed/2026-01/traj_cuuwpd2q5rr4.json
  • .agentworkforce/trajectories/completed/2026-01/traj_cuuwpd2q5rr4.md
  • .agentworkforce/trajectories/completed/2026-01/traj_cuuwpd2q5rr4.trace.json
  • .agentworkforce/trajectories/completed/2026-02/traj_gtzye0t83h5a.json
  • .agentworkforce/trajectories/completed/2026-02/traj_gtzye0t83h5a.md
  • .agentworkforce/trajectories/completed/traj_1775579377702_4f7f9060.json
  • .agentworkforce/trajectories/completed/traj_1775579377702_d7c0960f.json
  • .agentworkforce/trajectories/completed/traj_1775579377703_10fca7cd.json
  • .agentworkforce/trajectories/completed/traj_1775579517021_75d423d8.json
  • .agentworkforce/trajectories/completed/traj_1775579517022_56a8cb51.json
  • .agentworkforce/trajectories/completed/traj_1775579517022_f0443bc4.json
  • .agentworkforce/trajectories/completed/traj_1775579517024_ea9370c2.json
  • .agentworkforce/trajectories/completed/traj_1775579684459_bcfd075c.json
  • .agentworkforce/trajectories/completed/traj_1775579684464_082ed115.json
  • .agentworkforce/trajectories/completed/traj_1775579684464_c956bacd.json
  • .agentworkforce/trajectories/completed/traj_1775579684472_6903a2a5.json
  • .agentworkforce/trajectories/completed/traj_1775579684472_fdc465b2.json
  • .agentworkforce/trajectories/completed/traj_1775579684476_a9b5c6b9.json
  • .agentworkforce/trajectories/completed/traj_1775579883001_419efbfc.json
  • .agentworkforce/trajectories/completed/traj_1775579883001_f31aa87b.json
  • .agentworkforce/trajectories/completed/traj_1775579883004_197f89a2.json
  • .agentworkforce/trajectories/completed/traj_1775579883005_c0fcdbcb.json
  • .agentworkforce/trajectories/completed/traj_1775580030112_0bf91d39.json
  • .agentworkforce/trajectories/completed/traj_1775580030115_38fdd60c.json
  • .agentworkforce/trajectories/completed/traj_1775580030115_6ae8429d.json
  • .agentworkforce/trajectories/completed/traj_1775580030115_ec4e7106.json
  • .agentworkforce/trajectories/completed/traj_1775580241282_2cf5e535.json
  • .agentworkforce/trajectories/completed/traj_1775580241282_2d95f122.json
  • .agentworkforce/trajectories/completed/traj_1775580241282_b0bf263f.json
  • .agentworkforce/trajectories/completed/traj_1775580241287_3c613873.json
  • .agentworkforce/trajectories/completed/traj_1775580409392_3bf04f3e.json
  • .agentworkforce/trajectories/completed/traj_1775580409397_48a4a2ba.json
  • .agentworkforce/trajectories/completed/traj_1775580409400_2fc46843.json
  • .agentworkforce/trajectories/completed/traj_1775580409401_2cfac72a.json
  • .agentworkforce/trajectories/completed/traj_1775580409403_e09bc229.json
  • .agentworkforce/trajectories/completed/traj_1775580587438_bf5ed89a.json
  • .agentworkforce/trajectories/completed/traj_1775580587441_5dac7a03.json
  • .agentworkforce/trajectories/completed/traj_1775580587441_8253d528.json
  • .agentworkforce/trajectories/completed/traj_1775580587445_c0a442b5.json
  • .agentworkforce/trajectories/completed/traj_1775580824527_e441d22f.json
  • .agentworkforce/trajectories/completed/traj_1775581182381_f4b36b94.json
  • .agentworkforce/trajectories/completed/traj_1775581182382_04a32af5.json
  • .agentworkforce/trajectories/completed/traj_1775581182382_b0db75c5.json
  • .agentworkforce/trajectories/completed/traj_1775581547975_63b4aab0.json
  • .agentworkforce/trajectories/completed/traj_1775581806172_0bfbf365.json
  • .agentworkforce/trajectories/completed/traj_1775582004453_91203e94.json
  • .agentworkforce/trajectories/completed/traj_1775582241963_3a261e62.json
  • .agentworkforce/trajectories/completed/traj_1775582692229_21d871cb.json
  • .agentworkforce/trajectories/completed/traj_1775582848710_1c41743b.json
  • .agentworkforce/trajectories/completed/traj_1775582995462_aa15ac06.json
  • .agentworkforce/trajectories/completed/traj_1775583188684_0f5f6c47.json
  • .agentworkforce/trajectories/completed/traj_1775583188688_d4d12d64.json
  • .agentworkforce/trajectories/completed/traj_1775583188695_5f6d0186.json
  • .agentworkforce/trajectories/completed/traj_1775583188696_a2babaa9.json
  • .agentworkforce/trajectories/completed/traj_1775583188698_4500ed85.json
  • .agentworkforce/trajectories/completed/traj_1775583478300_8b5d0d45.json
  • .agentworkforce/trajectories/completed/traj_1775587484181_8d5f9706.json
  • .agentworkforce/trajectories/completed/traj_1775587484181_ade8f314.json
  • .agentworkforce/trajectories/completed/traj_1775587484181_f47c4bb8.json
  • .agentworkforce/trajectories/completed/traj_1775587754098_777acf8b.json
  • .agentworkforce/trajectories/completed/traj_1775587754098_99381421.json
  • .agentworkforce/trajectories/completed/traj_1775587754099_2e24aa44.json
  • .agentworkforce/trajectories/completed/traj_1775587942028_d7c657ee.json
  • .agentworkforce/trajectories/completed/traj_1775587942028_edac5455.json
  • .agentworkforce/trajectories/completed/traj_1775587942029_ae2b3a94.json
  • .agentworkforce/trajectories/completed/traj_1775587942032_8e4dc570.json
  • .agentworkforce/trajectories/completed/traj_1775588202995_1c36a335.json
  • .agentworkforce/trajectories/completed/traj_1775588319448_b188885f.json
  • .agentworkforce/trajectories/completed/traj_1775588443144_269a6c7b.json
  • .agentworkforce/trajectories/completed/traj_1775588658881_9013c72e.json
  • .agentworkforce/trajectories/completed/traj_1775588795733_442cdf75.json
  • .agentworkforce/trajectories/completed/traj_1775588982963_ae82593f.json
  • .agentworkforce/trajectories/completed/traj_1775589139752_34e57999.json
  • .agentworkforce/trajectories/completed/traj_1775589353412_b854336d.json
  • .agentworkforce/trajectories/completed/traj_1775589539846_210c5b03.json
  • .agentworkforce/trajectories/completed/traj_1775589539846_468c4604.json
  • .agentworkforce/trajectories/completed/traj_1775589539847_fcc1e72b.json
  • .agentworkforce/trajectories/completed/traj_1775589539853_64dd4d34.json
  • .agentworkforce/trajectories/completed/traj_1775589892159_2d684c41.json
  • .agentworkforce/trajectories/completed/traj_1775589892159_7437e0b3.json
  • .agentworkforce/trajectories/completed/traj_1775589892160_65fa5491.json
  • .agentworkforce/trajectories/completed/traj_1775589892162_7ee958ef.json
  • .agentworkforce/trajectories/completed/traj_1775590064833_71520399.json
  • .agentworkforce/trajectories/completed/traj_1775590064834_91431f8f.json
  • .agentworkforce/trajectories/completed/traj_1775590554286_8f755680.json
  • .agentworkforce/trajectories/completed/traj_1775590554286_bbbf5e8e.json
  • .agentworkforce/trajectories/completed/traj_1775590554287_78bfeb4f.json
  • .agentworkforce/trajectories/completed/traj_1775592035208_089f3045.json
  • .agentworkforce/trajectories/completed/traj_1775592035208_59779aa9.json
  • .agentworkforce/trajectories/completed/traj_1775592035208_9e1d2cdd.json
  • .agentworkforce/trajectories/completed/traj_1775647089663_47b8475f.json
  • .agentworkforce/trajectories/completed/traj_1775654935435_4c3e7705.json
  • .agentworkforce/trajectories/completed/traj_1775656444666_4554590c.json
  • .agentworkforce/trajectories/completed/traj_1775656574638_d09f8bad.json
  • .agentworkforce/trajectories/completed/traj_1775660026655_968f3c47.json
  • .agentworkforce/trajectories/completed/traj_1775661295787_9aa27b54.json
  • .agentworkforce/trajectories/completed/traj_1775662772237_c9a1c6cf.json
  • .gitignore
  • .trajectories/index.json
  • AGENTS.md
  • IMPLEMENTATION-PROPOSAL.md
  • PROPOSAL-trajectories.md
  • README.md
  • biome.json
  • docs/architecture/core.md
  • docs/architecture/memory-integration.md
  • docs/architecture/web-viewer.md
  • package.json
  • scripts/benchmark-compaction.ts
  • src/cli/commands/compact.ts
  • src/cli/commands/complete.ts
  • src/cli/commands/doctor.ts
  • src/cli/commands/export.ts
  • src/compact/config.ts
  • src/core/trailers.ts
  • src/index.ts
  • src/sdk/client.ts
  • src/storage/file.ts
  • src/storage/index.ts
  • tests/compact/llm-compact.test.ts
  • tests/export/export.test.ts
  • tests/sdk/workflow-compact.test.ts
  • tests/storage/concurrent-save.test.ts
  • tests/storage/reconcile-real-data.test.ts
  • tests/storage/storage.test.ts
  • trail-viewer/Sources/AppConfiguration.swift
  • trail-viewer/Sources/Services/LocalServerManager.swift
  • trail-viewer/Sources/Services/QuickLookGenerator.swift
  • trail-viewer/Sources/Services/SpotlightRegistration.swift
  • trail-viewer/Sources/Views/WelcomeView.swift
  • trail-viewer/server/src/trajectory-service.ts
  • workflows/compact-on-workflow-run.ts
  • workflows/fix-trajectory-schema/01-investigate.ts
  • workflows/fix-trajectory-schema/02-implement.ts
  • workflows/fix-trajectory-schema/README.md
  • workflows/llm-compaction.ts
  • workflows/sdk-autocompact-option.ts
  • workflows/sdk-workflow-autocompact.ts
💤 Files with no reviewable changes (1)
  • .trajectories/index.json

Comment thread PROPOSAL-trajectories.md

### File System (Default)

```
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a language to the fenced code block at Line 1139.

Markdownlint MD040 is triggered here; please annotate this fence (e.g., ```text) to keep doc lint clean.

Suggested fix
-```
+```text
 .agentworkforce/trajectories/
 ├── index.json                    # Quick lookup index
 ...
</details>

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 markdownlint-cli2 (0.22.1)</summary>

[warning] 1139-1139: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

</details>

</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @PROPOSAL-trajectories.md at line 1139, Update the fenced code block showing
the directory tree for ".agentworkforce/trajectories/" by adding a language
identifier (e.g., text) to the opening fence so Markdownlint MD040 is satisfied; locate the fenced block that begins with the line ".agentworkforce/trajectories/" and change the opening to include the
language token (such as text) so the block becomes fenced with ```text.


</details>

<!-- fingerprinting:phantom:triton:hawk -->

<!-- This is an auto-generated comment by CodeRabbit -->

Comment on lines +19 to +33
function isTrajectoryDataDir(path: string): boolean {
const normalized = path.replace(/[\\/]+$/, "");
const hasDataSubdirs =
existsSync(join(path, "active")) && existsSync(join(path, "completed"));

return normalized.endsWith(DEFAULT_TRAJECTORY_DATA_DIR) || hasDataSubdirs;
}

function resolveTrajectoryDataDir(path: string): string {
if (isTrajectoryDataDir(path)) {
return path;
}

return join(path, DEFAULT_TRAJECTORY_DATA_DIR);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add legacy repo-root fallback in resolveTrajectoryDataDir.

For repo roots that still store data in ./.trajectories, this resolver always points to ./.agentworkforce/trajectories, which can make existing trajectories appear missing after switchDataDir.

Suggested fix
 function resolveTrajectoryDataDir(path: string): string {
   if (isTrajectoryDataDir(path)) {
     return path;
   }
 
+  const legacy = join(path, ".trajectories");
+  const legacyLooksLikeDataDir =
+    existsSync(join(legacy, "active")) && existsSync(join(legacy, "completed"));
+  if (legacyLooksLikeDataDir) {
+    return legacy;
+  }
+
   return join(path, DEFAULT_TRAJECTORY_DATA_DIR);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@trail-viewer/server/src/trajectory-service.ts` around lines 19 - 33, The
resolver currently only recognizes DEFAULT_TRAJECTORY_DATA_DIR and will
incorrectly redirect repo roots that still use the legacy "./.trajectories"
folder; update isTrajectoryDataDir and resolveTrajectoryDataDir to treat the
legacy name as a valid data dir. Modify isTrajectoryDataDir to also detect the
legacy folder (e.g., check existsSync(join(path, ".trajectories")) or
normalized.endsWith(".trajectories")), and change resolveTrajectoryDataDir to
return the legacy path when that folder exists on the repo root (before falling
back to join(path, DEFAULT_TRAJECTORY_DATA_DIR)), using the existing function
names isTrajectoryDataDir and resolveTrajectoryDataDir for locating where to
apply the change.

Comment on lines 92 to 94
const dataDir = process.env.TRAJECTORIES_DATA_DIR;
const trajDir = dataDir ?? join(this.dataDir, ".trajectories");
const trajDir = dataDir ?? join(this.dataDir, DEFAULT_TRAJECTORY_DATA_DIR);
const completedDir = join(trajDir, "completed");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use the same directory resolver in index/read paths.

rebuildIndex and getTrajectory currently append DEFAULT_TRAJECTORY_DATA_DIR directly when env is unset. If this.dataDir is already a trajectory data dir, this produces an invalid nested path.

Suggested fix
-    const dataDir = process.env.TRAJECTORIES_DATA_DIR;
-    const trajDir = dataDir ?? join(this.dataDir, DEFAULT_TRAJECTORY_DATA_DIR);
+    const baseDir = process.env.TRAJECTORIES_DATA_DIR ?? this.dataDir;
+    const trajDir = resolveTrajectoryDataDir(baseDir);
@@
-    const dataDir = process.env.TRAJECTORIES_DATA_DIR;
-    const trajDir = dataDir ?? join(this.dataDir, DEFAULT_TRAJECTORY_DATA_DIR);
+    const baseDir = process.env.TRAJECTORIES_DATA_DIR ?? this.dataDir;
+    const trajDir = resolveTrajectoryDataDir(baseDir);

Also applies to: 331-333

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@trail-viewer/server/src/trajectory-service.ts` around lines 92 - 94, The code
builds trajDir by blindly appending DEFAULT_TRAJECTORY_DATA_DIR to this.dataDir
which double-nests when this.dataDir already points to the trajectory directory;
change the resolver to pick the base dir = process.env.TRAJECTORIES_DATA_DIR ??
this.dataDir and then only append DEFAULT_TRAJECTORY_DATA_DIR if the base's
final path segment is not already DEFAULT_TRAJECTORY_DATA_DIR (e.g. check
path.basename(base) !== DEFAULT_TRAJECTORY_DATA_DIR), then set trajDir = base or
join(base, DEFAULT_TRAJECTORY_DATA_DIR) and compute completedDir from trajDir;
apply the same change in rebuildIndex and getTrajectory to use the same
resolution logic.

Comment on lines +125 to +146
// The SDK uses TRAJECTORIES_DATA_DIR directly as the data directory.
// If the user picked a repo root, append the default data path.
let selected = URL(fileURLWithPath: trajectoryPath)
let trajDirURL = selected
.appendingPathComponent(".agentworkforce", isDirectory: true)
.appendingPathComponent("trajectories", isDirectory: true)
let isDefaultDataDir = selected.lastPathComponent == "trajectories" &&
selected.deletingLastPathComponent().lastPathComponent == ".agentworkforce"
let hasActiveDir = FileManager.default.fileExists(
atPath: selected.appendingPathComponent("active", isDirectory: true).path
)
let hasCompletedDir = FileManager.default.fileExists(
atPath: selected.appendingPathComponent("completed", isDirectory: true).path
)
let hasTrajectoryChildren = hasActiveDir && hasCompletedDir
let resolvedTrajectoryPath: String
if isDefaultDataDir || hasTrajectoryChildren {
resolvedTrajectoryPath = trajectoryPath
} else {
environment["TRAJECTORIES_DATA_DIR"] = trajectoryPath
resolvedTrajectoryPath = trajDirURL.path
}
environment["TRAJECTORIES_DATA_DIR"] = resolvedTrajectoryPath
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve repo-root fallback for legacy .trajectories data.

When a repo root is selected and only ./.trajectories exists, this branch resolves to ./.agentworkforce/trajectories, which can hide existing legacy data instead of serving it.

Suggested fix
         if let trajectoryPath {
             // The SDK uses TRAJECTORIES_DATA_DIR directly as the data directory.
             // If the user picked a repo root, append the default data path.
             let selected = URL(fileURLWithPath: trajectoryPath)
             let trajDirURL = selected
                 .appendingPathComponent(".agentworkforce", isDirectory: true)
                 .appendingPathComponent("trajectories", isDirectory: true)
+            let legacyTrajDirURL = selected.appendingPathComponent(".trajectories", isDirectory: true)
             let isDefaultDataDir = selected.lastPathComponent == "trajectories" &&
                 selected.deletingLastPathComponent().lastPathComponent == ".agentworkforce"
             let hasActiveDir = FileManager.default.fileExists(
                 atPath: selected.appendingPathComponent("active", isDirectory: true).path
             )
             let hasCompletedDir = FileManager.default.fileExists(
                 atPath: selected.appendingPathComponent("completed", isDirectory: true).path
             )
             let hasTrajectoryChildren = hasActiveDir && hasCompletedDir
+            let hasLegacyChildren =
+                FileManager.default.fileExists(
+                    atPath: legacyTrajDirURL.appendingPathComponent("active", isDirectory: true).path
+                ) &&
+                FileManager.default.fileExists(
+                    atPath: legacyTrajDirURL.appendingPathComponent("completed", isDirectory: true).path
+                )
             let resolvedTrajectoryPath: String
             if isDefaultDataDir || hasTrajectoryChildren {
                 resolvedTrajectoryPath = trajectoryPath
+            } else if hasLegacyChildren {
+                resolvedTrajectoryPath = legacyTrajDirURL.path
             } else {
                 resolvedTrajectoryPath = trajDirURL.path
             }
             environment["TRAJECTORIES_DATA_DIR"] = resolvedTrajectoryPath
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// The SDK uses TRAJECTORIES_DATA_DIR directly as the data directory.
// If the user picked a repo root, append the default data path.
let selected = URL(fileURLWithPath: trajectoryPath)
let trajDirURL = selected
.appendingPathComponent(".agentworkforce", isDirectory: true)
.appendingPathComponent("trajectories", isDirectory: true)
let isDefaultDataDir = selected.lastPathComponent == "trajectories" &&
selected.deletingLastPathComponent().lastPathComponent == ".agentworkforce"
let hasActiveDir = FileManager.default.fileExists(
atPath: selected.appendingPathComponent("active", isDirectory: true).path
)
let hasCompletedDir = FileManager.default.fileExists(
atPath: selected.appendingPathComponent("completed", isDirectory: true).path
)
let hasTrajectoryChildren = hasActiveDir && hasCompletedDir
let resolvedTrajectoryPath: String
if isDefaultDataDir || hasTrajectoryChildren {
resolvedTrajectoryPath = trajectoryPath
} else {
environment["TRAJECTORIES_DATA_DIR"] = trajectoryPath
resolvedTrajectoryPath = trajDirURL.path
}
environment["TRAJECTORIES_DATA_DIR"] = resolvedTrajectoryPath
// The SDK uses TRAJECTORIES_DATA_DIR directly as the data directory.
// If the user picked a repo root, append the default data path.
let selected = URL(fileURLWithPath: trajectoryPath)
let trajDirURL = selected
.appendingPathComponent(".agentworkforce", isDirectory: true)
.appendingPathComponent("trajectories", isDirectory: true)
let legacyTrajDirURL = selected.appendingPathComponent(".trajectories", isDirectory: true)
let isDefaultDataDir = selected.lastPathComponent == "trajectories" &&
selected.deletingLastPathComponent().lastPathComponent == ".agentworkforce"
let hasActiveDir = FileManager.default.fileExists(
atPath: selected.appendingPathComponent("active", isDirectory: true).path
)
let hasCompletedDir = FileManager.default.fileExists(
atPath: selected.appendingPathComponent("completed", isDirectory: true).path
)
let hasTrajectoryChildren = hasActiveDir && hasCompletedDir
let hasLegacyChildren =
FileManager.default.fileExists(
atPath: legacyTrajDirURL.appendingPathComponent("active", isDirectory: true).path
) &&
FileManager.default.fileExists(
atPath: legacyTrajDirURL.appendingPathComponent("completed", isDirectory: true).path
)
let resolvedTrajectoryPath: String
if isDefaultDataDir || hasTrajectoryChildren {
resolvedTrajectoryPath = trajectoryPath
} else if hasLegacyChildren {
resolvedTrajectoryPath = legacyTrajDirURL.path
} else {
resolvedTrajectoryPath = trajDirURL.path
}
environment["TRAJECTORIES_DATA_DIR"] = resolvedTrajectoryPath
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@trail-viewer/Sources/Services/LocalServerManager.swift` around lines 125 -
146, The code in LocalServerManager.swift determines TRAJECTORIES_DATA_DIR using
selected, trajDirURL, isDefaultDataDir, hasActiveDir, hasCompletedDir and falls
back to trajDirURL.path, but it doesn't detect legacy repos that have a
top-level ".trajectories" directory; add a check for
selected.appendingPathComponent(".trajectories", isDirectory: true) (e.g., let
hasLegacyTrajectories = FileManager.default.fileExists(atPath:
selected.appendingPathComponent(".trajectories").path)) and incorporate it into
the resolution logic so that if hasLegacyTrajectories is true you set
resolvedTrajectoryPath to selected.appendingPathComponent(".trajectories").path
(preserving the existing behavior for isDefaultDataDir or hasTrajectoryChildren
otherwise) before assigning environment["TRAJECTORIES_DATA_DIR"].

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 4 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="trail-viewer/Sources/Services/LocalServerManager.swift">

<violation number="1" location="trail-viewer/Sources/Services/LocalServerManager.swift:139">
P2: Using `&&` here can incorrectly reject a valid trajectories directory when only one child folder exists, causing the resolved path to be rewritten to a nested `.agentworkforce/trajectories` location.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

let hasCompletedDir = FileManager.default.fileExists(
atPath: selected.appendingPathComponent("completed", isDirectory: true).path
)
let hasTrajectoryChildren = hasActiveDir && hasCompletedDir
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Using && here can incorrectly reject a valid trajectories directory when only one child folder exists, causing the resolved path to be rewritten to a nested .agentworkforce/trajectories location.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At trail-viewer/Sources/Services/LocalServerManager.swift, line 139:

<comment>Using `&&` here can incorrectly reject a valid trajectories directory when only one child folder exists, causing the resolved path to be rewritten to a nested `.agentworkforce/trajectories` location.</comment>

<file context>
@@ -130,13 +130,13 @@ final class LocalServerManager {
-            ) || FileManager.default.fileExists(
-                atPath: selected.appendingPathComponent("index.json").path
             )
+            let hasTrajectoryChildren = hasActiveDir && hasCompletedDir
             let resolvedTrajectoryPath: String
             if isDefaultDataDir || hasTrajectoryChildren {
</file context>
Suggested change
let hasTrajectoryChildren = hasActiveDir && hasCompletedDir
let hasTrajectoryChildren = hasActiveDir || hasCompletedDir

@willwashburn willwashburn merged commit 4787f74 into main May 26, 2026
8 checks passed
@willwashburn willwashburn deleted the codex/move-agentworkforce-trajectories branch May 26, 2026 01:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant