[feat] Pin a workspace to a team ref with `teamai pull --team-ref`
Maintainers usually reply within 1 day
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 8/100
- Issue type
- Feature
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- git, typescript
Research direction
Start from the --team-ref option in index.ts, then read the pull flow in pull.ts (the scope check near line 2877), pullRepo and getDefaultBranch in utils/git.ts (lines 456 and 531), and detectProjectConfig in config.ts. The push rule lives in push.ts (syncTeamUpdatesToLocal) and removal in resources/delivered-copies.ts (judgeRemoval). Done means acceptance criteria 1 to 12 pass, including the e2e cases built with teamCommit.
Written by the indexing model from the issue text.
Description
Goal
teamai pull always delivers the team repo's default branch. A member cannot try a team branch in a workspace before it merges, or keep a workspace on a known team commit. A benchmark (#1180, #1181) cannot prepare a trial workspace with a given commit's assets either.
Add --team-ref <ref> to teamai pull. It pins the workspace the command runs in to that ref of the team repo. Every later pull in that workspace delivers the same ref, including the pulls hooks run, until the workspace is pinned to the default branch again.
teamai pull --team-ref feature/review-skill # follow a branch
teamai pull --team-ref v2.3.0 # stay on a tag
teamai pull --team-ref 3f2c9a7d # stay on a commit
teamai pull --team-ref main # the default branch: unpin
Rules
- The pin belongs to the workspace. A workspace, set up with
teamai init --scope workspace, has its own clone of the team repo (<data home>/team-repo), which all checkouts and worktrees of its repository share. A pinned pull fetches, then checks that clone out, detached, at the resolved commit, instead of fast-forwarding it on its branch. Everything that reads the clone then follows the pin with no change of its own: the delivery, the "Already synced" fast path, the session-start hooks that serve team rules and instructions, team hooks, MCP, env, the search index and the workflow cache. The pin is stored in the workspace's local config asrepo.ref, the ref as the member passed it. It is not committed, and other members' workspaces are not pinned. - Every pull in the workspace honors it:
teamai pull, the session-start, new-worktree and git-pull hooks, and the detached pull a git hook starts afterwards. - What a ref can be. A branch of the team repo's remote, a tag, or a commit, resolved in the workspace's clone after the fetch, in this order:
origin/<ref>, a tag, a commit. A commit is a hexadecimal object name of at least 7 characters, reachable from a remote-tracking branch, so any machine with the team repo can deliver it. The resolved commit must holdteamai.yaml. Anything else fails, such as a local branch of the clone,origin/main,HEAD~1, or the tip ofteamai-reports:Team ref "<ref>" is not a branch, tag or commit of the team repo that holds teamai.yaml. Branches: <remote-tracking branches, without teamai-reports and teamai-learnings>. Push it, or check the name. - A branch follows its tip; a tag or a commit stays put. Each pull of a workspace pinned to a branch delivers the branch's current commit.
- Unpin by passing the default branch, the name
getDefaultBranchreturns (utils/git.ts:531). The config dropsrepo.ref, the clone goes back to its branch and fast-forwards, and the pull delivers the default branch as before. A copy the member changed while pinned is kept, as any pull keeps one, and the unpin says it holds ""'s content, whichteamai pushwould send to the default branch. - Switching revision removes what the new one lacks. A pull that delivers another commit than a checkout's record
revbecause of a pin, a re-pin or an unpin also removes each skill, rule and agent copy the record lists indeliveredthat the new commit does not deliver, whenjudgeRemoval(resources/delivered-copies.ts) says it is unchanged. A copy the member changed is kept and named, as a pull names it today. Removal today follows the team's tombstones and the names the current tree knows, and a branch that deletes or adds a skill gives neither. - Recorded. Each checkout's record
revis the delivered commit, in the form it has today, so #1176 records it asagent.team.revision. - Where it applies. Only to a workspace with a standalone git team repo (
repo.kindgitor omitted). Every pull of a pinned workspace checks this before the user-scope step (pull.ts:2877), not only the pull that sets the pin. Each other case fails before anything is delivered, keeps the pin, and has its own message:- no workspace config for the directory, as in a fresh clone (
detectProjectConfig,config.ts):--team-ref needs a teamai workspace here. Run teamai init --scope workspace here first.; - the same team repo at user scope (a user-scope config whose
repo.remotematches,remotesMatch,utils/git.ts:343), or a workspace that inherits user scope (inheritUserScope):--team-ref pins one workspace, but this team also reaches it through user scope, where every workspace shares one copy. Remove the user-scope install, or turn off inheritUserScope, to pin a workspace.; - single-repo mode (
self):--team-ref does not apply in single-repo mode: the project's own commit decides which team assets it has.; - an HTTP team repo (
http):--team-ref needs a git team repo. This team is served over HTTP.
- no workspace config for the directory, as in a fresh clone (
- Exit status.
teamai pull --team-ref, and any pull of a pinned workspace, exits 1 unless every checkout it delivers to ends at the resolved commit with its delivery complete. A ref that does not resolve, a failed check above, a failed fetch, a scope another pull has locked, or an incomplete delivery (docs, submodules, a held agent) each exit 1. A driver that prepares a workspace with it relies on this. - Push. In a pinned workspace,
teamai pushdoes not send skill, rule or agent changes, because they were made on top of another revision than the default branch. It also does not run the pre-push sync, which would bring the checkout's unedited copies to the default branch (syncTeamUpdatesToLocalinpush.ts), and records no push base. It says:This workspace is pinned to team ref "<ref>", so its skill, rule and agent changes were not pushed: they were made on top of "<ref>". Commit them to "<ref>" in the team repo, or make them again in a workspace that follows the default branch.Pinning does not change how stats, votes and learnings reach the team: pull reports them, as it does today. - Visible. Every non-silent pull of a pinned workspace prints
Pinned to team ref "<ref>" at <short commit>. Run teamai pull --team-ref <default branch> to follow the default branch again.teamai statusshows the same line.
Scope
--team-ref <ref>onpull(index.ts), with help text that says it pins the workspace.- Resolution,
repo.refin the workspace's local config, the detached checkout of the workspace's clone, the unpin, and the removal on a switch. - The scope and kind checks on every pull of a pinned workspace, the exit status, the push rule, the pull output line and the line in
status. docs/guide/distribution.mdanddocs/guide/zh-CN/distribution.md: a short section on pinning a workspace.- Regenerate
skill-data/core/references/commands.mdwithnpx vitest run commands-reference -u.
Acceptance criteria
teamai pull --team-ref <branch>delivers a skill that exists only on that branch, and a rule that the branch changes arrives with the branch's content.- A later plain
teamai pull, the pull the session-start hook runs, and the pull the git-pull hook runs keep delivering the branch, also afterteamai tags subscribe <tag>. After a new commit is pushed to the branch, the next pull delivers it. - A tag pin and a commit pin each deliver the same commit after new commits land on the default branch.
teamai pull --team-ref <default branch>unpins. The next pull delivers the default branch, the unedited copy of the skill criterion 1 delivered is gone, an edited one is kept with its message, and the config has norepo.ref. Pinning to a branch that deletes a skill removes that skill's unedited copies.- Every checkout of a pinned workspace gets the pinned commit, including a worktree created after the pin. Another workspace of the same member on the same team, and the user scope's clone, keep the default branch.
- An unknown ref, a commit not reachable from a remote-tracking branch,
origin/main, andteamai-reportseach fail with the message above, exit 1, and change nothing in the workspace. A pinned pull whose fetch fails exits 1 too. - A fresh clone without teamai set up, the same team at user scope,
inheritUserScope,selfandhttpeach fail with their message, and nothing is delivered. Turning oninheritUserScopeafter pinning makes the next pull fail the same way and keeps the pin. - In a pinned workspace with an edited skill,
teamai pushpushes no asset change, leaves the checkout's delivered files as they were, and prints the message. The nextteamai pullthere still reports its usage stats. - Each checkout record's
revis the delivered commit. With #1176 merged, a workflow step run in that workspace records it asagent.team.revision. - In a fresh clone of the project with no remotes, in a temporary directory,
teamai pull --team-ref <commit>fails with the set-up message and writes nothing. Afterteamai init <team repo> --scope workspacethere with the same team repo, the same command delivers that commit's assets. This is how #1180 prepares a trial. - A second pull of a pinned workspace with nothing new takes the "Already synced" path, and Claude Code and Codex sessions started there get the pinned commit's rules and instructions from their session-start hooks.
teamai statusin a pinned workspace shows the pin line, counts team resources at the pinned commit, and does not list a skill only the pinned branch has among the local resources not yet pushed.
Test plan
- Unit tests for ref resolution,
repo.refin the config, and the scope checks. - E2E with a fixture team repo that has a branch and a tag, built the way the
*-915e2e tests build theirs (teamCommit), for criteria 1 to 8 and 10 to 12, and the second sentence of criterion 9 once #1176 is merged. - One real-CLI run for the PR body: pin a workspace to a team branch, start a Claude session, and show the branch's skill in the session.
Watch out for
pullRepo(utils/git.ts:456) runsgit pull --ff-onlyand recovers with a hard reset toorigin/<current branch>. Neither works on a detachedHEAD. A pinned pull fetches and checks out the commit detached. An unpin checks out the default branch and fast-forwards it.- Check every writer of the workspace's clone, such as queued learnings and push branches, while the clone is detached. Each one keeps working or skips with a message. None may commit on top of the pinned commit.
- Submodules follow the pinned commit's pins.
- An older CLI that saves the local config drops fields it does not know, and so drops
repo.ref. Say so in the release notes.
Out of scope
- A pin committed to the project, so that every member's pull follows it.
- Pinning one checkout of a workspace apart from the others.
- Pinning the user scope, or cross-team
sources.
Dependencies
- Blocked by: none
- Unblocks: #1180
- Dominant language
- TypeScript
- Stars
- 5.6k
- Forks
- 471
- Avg merge
- 22h 54m
- Merged PRs (30d)
- 347
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from Tencent/teamai-cli
-
enhancement question
Difficulty 5/5 Over a week Newbie friendliness 45/100
Tencent/teamai-cli#1429 · 1 comment ·
Maintainers usually reply within 1 day
-
enhancement
Difficulty 4/5 3-5 days Newbie friendliness 45/100
Tencent/teamai-cli#1426 · 1 comment ·
Maintainers usually reply within 1 day
-
[bug] Codebase import: --skip-enrich drops AI enrichment, same-name --dir checkouts collide, and deep enrich follows symlinksPossibly taken A pull request linked to this issue is open or already merged. Openbug help wanted
Difficulty 4/5 3-5 days Newbie friendliness 54/100
Tencent/teamai-cli#1422 · 3 comments ·
Maintainers usually reply within 1 day
-
enhancement
Difficulty 5/5 Over a week Newbie friendliness 35/100
Tencent/teamai-cli#1419 ·
Maintainers usually reply within 1 day
-
enhancement
Difficulty 5/5 Over a week Newbie friendliness 35/100
Tencent/teamai-cli#1418 ·
Maintainers usually reply within 1 day
All issues in Tencent/teamai-cli
Similar issues
-
category::task code priority::normal
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
e0ipso/strikethroo#145 ·
Maintainers usually reply within 1 day
-
Difficulty 1/5 1-3 hours Newbie friendliness 85/100
cocos/cocos-docs#3333 ·
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
RevenueCat/react-native-purchases#2079 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
RevenueCat/purchases-hybrid-common#2039 ·
Maintainers usually reply within 1 day
-
agent-reported area/react bug
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
Maintainers usually reply within 1 day