Skip to content

fix: sync team resources before AI sessions start - #964

Open
SaulMoro wants to merge 15 commits into
Tencent:mainfrom
SaulMoro:feat/sync-before-session
Open

SaulMoro wants to merge 15 commits into
Tencent:mainfrom
SaulMoro:feat/sync-before-session

Conversation

@SaulMoro

@SaulMoro SaulMoro commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Prepare the team's supported resources before the AI tool reads its startup configuration.

flowchart TB
    subgraph CURRENT[Before]
        direction LR
        C1[Start tool] --> C2[Read startup config] --> C3[SessionStart pull] --> C4[Resources arrive late]
    end
    subgraph EXPECTED[After]
        direction LR
        E1[init / new worktree / git pull] --> E2[Prepare resources] --> E3[Start tool] --> E4[Read prepared config]
    end
    CURRENT ~~~ EXPECTED
    classDef sync fill:#6a4f8f,stroke:#513b6d,color:#fff;
    classDef late fill:#a33a3a,stroke:#7a2a2a,color:#fff;
    classDef ready fill:#2f8f4f,stroke:#1f6b39,color:#fff;
    class C3,E2 sync;
    class C2,C4 late;
    class E3,E4 ready;
    style CURRENT fill:#fff5f4,stroke:#a33a3a,color:#3a2525
    style EXPECTED fill:#f1faf3,stroke:#2f8f4f,color:#183e22
Loading

init finishes with a pull in both scopes. Project Git hooks prepare worktrees and apply updates after git pull. Startup delivery runs inline; the full refresh runs in the background.

Interactive init without --agent

Reuses single-repo mode's existing promptForSelfModeAgents. This PR adds the project call and wording.

$ teamai init https://git.example.com/team/team.git --scope project

Which AI tools do you use in this project?
(creates their tool dirs here and syncs the team's resources into them)

  1. Auto — the AI tools already installed here: Claude Code, Codex CLI
  2. Claude Code  (.claude)
  3. Codex CLI  (.codex)
  4. Cursor  (.cursor)
  5. Copilot  (.copilot)
  6. Pi Coding Agent  (.pi)
  7. JoyCode  (.joycode)
  8. CodeBuddy  (.codebuddy)
  9. WorkBuddy  (.workbuddy)

Select [1-9, comma/range, or "all"] (default: 1 = Auto): 2

Choice 2 enables Claude, creates only .claude/, and fills it before exit. Enter selects Auto. Non-interactive init without --agent creates no roots.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature causing existing behavior to change)
  • Documentation only
  • Refactor / internal cleanup

Evidence

Before: startup reads configuration before delivery; team changes leave the previous resources on disk.

Claude startup
18.226  CLAUDE.md scanned
18.720  SessionStart hook completed

Team revision    Delivered skill / agent / rule / MCP / hook
v1 + pull        v1 / v1 / v1 / v1 / v1
v2, before sync  v1 / v1 / v1 / v1 / v1

After: all five resources pass. Codex parent and child both call MCP, with resource tokens absent from the prompt and no shell or file changes.

Prepared case Skills Agents Rules MCP Team hooks Check
Project init ✓ ✓ ✓ ✓ ✓ Real CLI, delivery before exit
User init, no separate pull ✓ ✓ ✓ ✓ ✓ Real CLI and Codex sessions
First session in a Git worktree ✓ ✓ ✓ ✓ ✓ Codex sessions
App script creates worktree through Git ✓ ✓ ✓ ✓ ✓ Real CLI, no login PATH or session
Team changed, then git pull ✓ ✓ ✓ ✓ ✓ Real CLI and Codex sessions, new tokens
User team changed, then pre-launch pull ✓ ✓ ✓ ✓ ✓ Codex sessions, new tokens
Subsequent prepared session ✓ ✓ ✓ ✓ ✓ Persisted Codex sessions
Subagent ✓ ✓ ✓ ✓ ✓ Child MCP metadata and hook events

Codex project MCP records combine this runtime at 6c330c00 with #954 at 48c77400 in a temporary test branch. Trust was configured in the fixture. #954 and #955 remain excluded; standalone project MCP and automatic hook trust are not claimed.

Test Plan

  • npx tsc --noEmit passes
  • npm run lint passes
  • npx vitest run passes, 7,207 passed and 1 skipped
  • Added/updated tests for the change
  • npm run build passes
  • Built CLI E2E: 28/28 pass at 49d16d22; CI runs the suite on the current head
  • Real interactive init without --agent, choice 2: all five resources delivered, only .claude/ created
npx vitest run --config vitest.e2e.config.ts --retry 0 \
  src/__tests__/e2e/git-hook-new-worktree.test.ts \
  src/__tests__/e2e/init-ends-with-pull.test.ts

Built-CLI checks cover init, worktrees, all five updated resources, hook coexistence, failures, dry-run and uninstall. Five Codex parent/child records cover the session cases above. Interactive init passed at 49d16d22. Build, unit tests, typecheck and lint pass at the current head.

Related Issues

Fixes #963.

Related delivery and trust work: #954, #955.

Merge Danger

Door: two-way

No schema migration. Uninstall removes TeamAI's Git hook entries and blocks.

Blast Radius: startup

Init, worktree creation and post-merge now wait for delivery. Hooks preserve Git's exit status; doctor and the next interactive pull report failures.

Notes for Reviewers

  • Git 2.54+ uses config hooks. Older Git uses marked shell blocks; manager-owned, non-shell, unreadable or non-executable hooks are left untouched and receive doctor advice.
  • The hooks skip teamai's own checkouts: the knowledge worktree a single-repo push creates under .teamai/, and the reports and learnings checkouts in the project data home.
  • If the Git hook cannot be installed, the agent hooks are still installed and the error names the fix: init reports it and still pulls; hooks inject exits non-zero.
  • A hook run that delivers nothing because the project config is unreadable, or that delivers only part of the resources, stays recorded until a complete sync; doctor and the next interactive pull report it.
  • A fresh cache can lag the remote. Post-merge fetch and lock waits each cap at 5 seconds, in single-repo mode too. Incomplete sync, rebase, no-merge pulls and team-only updates need pre-launch teamai pull.
  • Hosts that bypass Git hooks need preparation. For Codex, use the route below; native --worktree integration is out of scope.
git worktree add -b feature ../feature
cd ../feature
teamai pull
codex exec -C "$PWD" "..."

Active sessions may need restarting. Both usage guides and affected skills are updated.

SessionStart keeps seeding its one tool through seedProjectAgentRoot. The new
createProjectToolRoots takes a set of tools, defaulting to enabledAgents and,
when that is empty, to the tool roots the main checkout already has.
…oots

Project-scope init with --agent creates those tools' roots after saving
enabledAgents, then init runs the scope's pull so the first session has
the team's skills, rules and MCP servers. Without --agent no root is
created. Docs and setup skill stop telling members to pull after init.
…sh the rest after

The post-checkout pass now runs pull in an internal inline mode: it skips the
team repo fetch when the clone was fetched within the source TTL (24 h, new
last-fetch.json stamp beside the clone), reads subscribed sources from their
cached clones, waits for another pull's partition lock instead of skipping,
and leaves learnings, reports, usage reporting and post-pull scripts to a
detached full pull started after it.
The post-merge git hook now runs an inline pull. With a separate team repo it
fetches the team repo whatever its fetch stamp says, aborting the fetch after
5 s (internal fetchTimeoutMs pull option, AbortSignal into simple-git), and
delivers when the revision moved; a detached full pull then refreshes the
team repo past the cap, sources, learnings and reports. In single-repo mode it
delivers the working tree git pull updated, with no network and no detached
pull.
A failure inside the silent git hook (team fetch failed or hit the cap,
partition lock held past the inline wait, handler error) is written to
debug.log and recorded in the project partition. doctor names it with its
fix and reports whether the hook is installed; the next interactive pull
mentions it once; a successful hook pull, detached retry included, clears
it. The post-merge inline lock wait is capped at its fetch cap.
… init

Project-scope init in a terminal without --agent reuses the single-repo
tool picker (Auto = tools installed under HOME). The choice is added to
enabledAgents before the tool roots are created, so only the chosen
tools' roots appear and the closing pull fills them. --agent and
non-interactive runs skip the picker; the latter still create no root.
- Leave an unreadable or non-executable .git/hooks script alone instead of
  replacing or enabling it; doctor explains the fallback.
- Install the git hook after the agent hooks and propagate its failure with
  the fix; init reports it and still pulls, hooks inject exits non-zero.
- Record why a git hook synced nothing when the project config is unreadable.
- Cap the self-mode post-merge lock wait at the same 5 s as the fetch.
- Keep a partial delivery failure recorded until a complete sync.
- Join detached hook pulls before the e2e sandbox is removed.
Resolve refreshTeamRepo's options: keep inline/fetchTimeoutMs and add main's
dryRun guard for the self-mode .gitignore self-heal (Tencent#944).
Detection run inside <main>/.teamai/knowledge-wt resolves that worktree as
its own project root, so the config-based guard missed it: a self-mode push
fired post-checkout there, delivered into the disposable worktree and left a
detached pull running. Exclude the main checkout's .teamai/ for both git
events.
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.

[bug] AI sessions can start with missing or outdated team resources

1 participant