Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

[feat] Pin a workspace to a team ref with `teamai pull --team-ref`

Closed
#1,183 0 comments 0 reactions 1 assignee View on GitHub

Maintainers usually reply within 1 day

@SaulMoro is already working on this.

Since Oct 18, 2026.

  • #1207 by @SaulMoro — open

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
Domain
cli, devtools

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

enhancement

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 as repo.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 hold teamai.yaml. Anything else fails, such as a local branch of the clone, origin/main, HEAD~1, or the tip of teamai-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 getDefaultBranch returns (utils/git.ts:531). The config drops repo.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, which teamai push would send to the default branch.
  • Switching revision removes what the new one lacks. A pull that delivers another commit than a checkout's record rev because of a pin, a re-pin or an unpin also removes each skill, rule and agent copy the record lists in delivered that the new commit does not deliver, when judgeRemoval (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 rev is the delivered commit, in the form it has today, so #1176 records it as agent.team.revision.
  • Where it applies. Only to a workspace with a standalone git team repo (repo.kind git or 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.remote matches, 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.
  • 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 push does 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 (syncTeamUpdatesToLocal in push.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 status shows the same line.

Scope

  • --team-ref <ref> on pull (index.ts), with help text that says it pins the workspace.
  • Resolution, repo.ref in 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.md and docs/guide/zh-CN/distribution.md: a short section on pinning a workspace.
  • Regenerate skill-data/core/references/commands.md with npx vitest run commands-reference -u.

Acceptance criteria

  1. 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.
  2. 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 after teamai tags subscribe <tag>. After a new commit is pushed to the branch, the next pull delivers it.
  3. A tag pin and a commit pin each deliver the same commit after new commits land on the default branch.
  4. 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 no repo.ref. Pinning to a branch that deletes a skill removes that skill's unedited copies.
  5. 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.
  6. An unknown ref, a commit not reachable from a remote-tracking branch, origin/main, and teamai-reports each fail with the message above, exit 1, and change nothing in the workspace. A pinned pull whose fetch fails exits 1 too.
  7. A fresh clone without teamai set up, the same team at user scope, inheritUserScope, self and http each fail with their message, and nothing is delivered. Turning on inheritUserScope after pinning makes the next pull fail the same way and keeps the pin.
  8. In a pinned workspace with an edited skill, teamai push pushes no asset change, leaves the checkout's delivered files as they were, and prints the message. The next teamai pull there still reports its usage stats.
  9. Each checkout record's rev is the delivered commit. With #1176 merged, a workflow step run in that workspace records it as agent.team.revision.
  10. 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. After teamai init <team repo> --scope workspace there with the same team repo, the same command delivers that commit's assets. This is how #1180 prepares a trial.
  11. 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.
  12. teamai status in 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.ref in the config, and the scope checks.
  • E2E with a fixture team repo that has a branch and a tag, built the way the *-915 e2e 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) runs git pull --ff-only and recovers with a hard reset to origin/<current branch>. Neither works on a detached HEAD. 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

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from Tencent/teamai-cli

All issues in Tencent/teamai-cli

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.