* fix(skills): one share gate, actionable refusals, and a louder stub deploy Follow-ups from the review of #699: - The Stop-hook reminder and `teamai skill get share` ask one gate (`shareGate`, through `contributeHintAllowed`). The hook skipped the unreadable-project-config check, and the legacy `teamai contribute-check` command, still called by hooks written before the dispatcher, checked nothing, so both nudged towards a command that refused. - The gate reads only a config load failure as "cannot be loaded"; any other fault propagates (the hook withholds the reminder and logs it at debug). - A `config` refusal says what failed (the file and position for a parse error) instead of pointing at `teamai doctor`, which cannot see a broken config. `skill show` now refuses through the same helper, so its hint moves from stdout to stderr like `skill get` and `skill path`. - `pull` warns when the discovery stub cannot be deployed (it was an empty catch on the fast path and a debug line on a full sync), and so does the legacy prune. - Error text no longer claims a reason was logged when none was: an empty config is named as empty, and `init` points at ~/.teamai/debug.log, where every path that deploys nothing now records why. - `core` routes a bare `/teamai` right after a friction reminder to `share`, as the stub already said. - The command drift guard rejects an unknown subcommand inside a group (`teamai skill gett core` passed before). - The contribute-check e2e asserts the reminder's real text again; the usage guides (EN, zh-CN) and the design doc cover the config refusal, the gate and the reminder routing. * test(learnings): retry temp-dir cleanup that races a detached git gc A push into the bare origin can leave `git gc --auto` writing to objects/pack after the test returns; the single rmdir in afterEach then fails with ENOTEMPTY (seen on CI, Node 22 ubuntu, #747). * fix(skills): gate skill show before its lookups, name the failing field Review of #747: - `skill show share` under a broken project config searched the user config's team repo and agents, which detection falls back to, and printed a `share` found there. It now asks the gate first and refuses on a config block before any lookup. With an empty user config it refuses instead of ending in a stack trace. - A config that parses but fails validation reported the Zod JSON dump, whose first line is `[`, so the refusal said `config.yaml: [.`. Every config loader now reports each issue as `field: reason` on one line. - The docs and skills that describe the share reminder or the refusal say it is withheld on a read-only source and while the config cannot be loaded, and that a validation failure names the field: product-overview and usage-guide (EN, zh-CN), designs/skill-serving.md, core/SKILL.md, contribute-member, setup-admin, join-member and manage-admin. * fix(skills): no share reminder where teamai is not set up `contributeHintAllowed` fell open with no config at all, so a caller other than the dispatcher (the legacy `teamai contribute-check`) still nudged in projects that never set up teamai, which have no team to share with (#748). It now returns false there. Serving the skill stays fail-open. * fix(contribute-check): gate the legacy reminder on the session's cwd `teamai contribute-check --stdin` asked the share gate about the directory the hook process started in, while the session analysis used the payload cwd. Started outside the project, it could read the user config and nudge where `teamai skill get share` refuses (a project config that does not load). It now moves to the payload cwd first, as hook-dispatch does. * fix(pull): keep a debug.log record when the stub cannot be deployed The previous commit turned both deploy catches into `log.warn`, which is muted in silent mode and never reaches debug.log, and a SessionStart pull runs detached with its output discarded. So the automatic pull, the one that deploys the stub for most members, lost the only persistent record it had. Both catches now warn and write the same line to debug.log. * fix(skills): skill show and list never answer for the fallback team Known issues left by #747: - `skill show <name>` and `skill list` on a config that exists but does not load ended in a Node stack trace, and under a broken project config they searched the user config detection falls back to: another team's repo and agents. Both now ask `detectTeam`, the one place that tells "this team", "no team" and "cannot tell, and why" apart (`shareGate` is built on it). Without a usable team, `show` answers from the package alone and `list` prints only the packaged catalog; both say what failed on stderr and exit 1. - A teamai.yaml that exists but fails validation was reported as "not found. Check your repo path". It is now named as invalid, empty or unreadable, like the local config. * fix(skills): the gate reads the session's directory, and no project config is skipped Codex review of5793758: - A project-location config that is not `scope: project` (or omits `scope`, which defaults to user) was skipped without a word, so the gate read past it to the user config. It is now reported as unusable, unless it is the user config itself, as when running from HOME. - The legacy `contribute-check` changed into the payload cwd and, if that failed, asked the gate about the directory the process started in. It now passes the payload cwd to the gate (`detectTeam(cwd)`), and a cwd that no longer exists holds no project config, so only the user config is asked, as #753 does. * fix(logger): record warnings in debug.log `log.warn` wrote to the console only and was muted in silent mode, so a detached SessionStart pull, whose output is discarded, lost every warning: the stub deploy failure and the legacy prune among them. Warnings now reach debug.log like debug and error lines. `warnStubNotDeployed` drops the second `log.debug` call, which printed the line twice under --verbose. * fix(skills): the dispatcher gate reads the payload cwd; a symlink is not HOME Codex review ofb0583f5: - The dispatcher's `contribute-check` and `pending-hint` handlers asked the gate about the process's directory, trusting hook-dispatch's `chdir`; when that failed, the launcher's config decided. They now pass `resolveHookCwd(stdin)`, as the legacy command does. - The HOME exception for a non-project scope compared the config file's real path, so a project config symlinked to ~/.teamai/config.yaml passed for the user config. It is now decided by the project's location: its root is HOME. * fix(skills): only a missing cwd falls back to the user config; load it once Codex review of15a5b5d: - `detectTeam` read any failure to see the payload cwd as "deleted", so a cwd it could not open (no permission, a path through a file) fell back to the user config and could allow the reminder. Only ENOENT does now; anything else is `unusable` and withholds it. - `skill show share` and `skill list` loaded the config twice, through the gate and then the team lookup, and reported a broken one twice. Both detect the team once and hand it to the gate. * fix(logger): a file-only record instead of persisting every warningb0583f5made every `log.warn` append to debug.log, wider than the two failures it was for, and it wrote unrelated subprocess errors to disk. `log.warn` is console-only again; `log.persist` writes one line to debug.log and never to the console. The stub deploy catches and the legacy prune catch use both, so a detached SessionStart pull keeps the record and --verbose prints it once.
10 KiB
TeamAI Product Overview
This document explains TeamAI's product architecture, supported agents, and core capabilities. For setup and day-to-day workflows, see the Usage Guide.
Product architecture
Team Execution × Team Context (beta) × Team Improvement (beta):
| Layer | Job | In this CLI today |
|---|---|---|
| Team Execution | Make every agent work the team's way | init / pull / push, skills, rules, agents, hooks, MCP, env |
| Team Context (beta) | Make every agent understand the team | recall, learnings, codebase graph, teamwiki... |
| Team Improvement (beta) | Make every execution improve the team | friction-based share-learnings, sessions, digest, dashboard... |
Overview
See the agent capability matrix in the README for what each agent supports.
Git providers — GitHub · GitLab · GitCode · CNB · TGit · private Git service.
Distribution Controls
Team-wide settings an admin configures once and delivers to every member on teamai pull:
| Capability | Command | What it does |
|---|---|---|
| Projects | teamai projects |
Bind a working directory to one or more logical projects so it syncs that project's skills, knowledge, and isolated learnings. Orthogonal to roles. |
| Roles | teamai roles |
Define role → namespace mappings so each member syncs only the skills for their role. |
| Tags | teamai tags |
Tag skills / rules so members subscribe to just the tags they need. |
| Sources | teamai source |
Subscribe to additional skill repos — other teams' public repos, or shared/public repos within your own org; subscribed skills sync automatically on pull. |
Learnings isolation: learnings/ at the repo root is shared with everyone; learnings/<project-id>/ is project-private. See the usage guide.
Team Execution
One Team. One Harness. Every Agent.
TeamAI keeps skills, rules, docs, and hooks in a shared git repo and distributes them to every member's local AI tools through a "push → review & merge → pull" flow — with support for subscribing to other teams' or shared repos' Harness.
How It Works
teamai push → create branch + MR → reviewer approves + merges
↓
SessionStart hook → teamai pull → synced to local AI tools
What Gets Shared
Each resource is delivered to every agent:
| Resource | In the team repo | Notes |
|---|---|---|
| Skills | skills/<name>/SKILL.md |
|
| Rules | rules/*.md |
|
| Docs | docs/ |
Foundational project docs; not all loaded by default (progressive disclosure) |
| Agents | agents/<name>.yaml, agents/<namespace>/<name>.yaml |
Root agents reach everyone; a namespace directory ships only to roles/projects that list it under agents: |
| Culture | culture.md |
Team mission, values, and working principles — injected into each agent's CLAUDE.md / AGENTS.md so every session inherits them |
| CLAUDE.md | claudemd/*.md |
|
| Env | env/ |
Shared team-level environment variables and switches; do not put secrets here. Each variable may carry roles: / projects: |
| Hooks | hooks/hooks.yaml |
Each hook may carry roles: / projects: to reach only members holding one of those roles and directories bound to one of those projects |
| MCP | mcp/mcp.yaml |
Each server may carry roles: / projects: to reach only members holding one of those roles and directories bound to one of those projects |
| Packages | teamai.yaml |
Currently npm packages and Claude Code plugins only |
| Models | — | Not implemented for every provider yet |
For file formats and full workflows, see the Usage Guide.
Team Context (beta)
Every agent understands how the team works.
Beyond distributing the Harness, TeamAI organizes accumulated team experience and code structure into a searchable knowledge base that the AI recalls automatically when needed.
Automatic Experience Sharing
When a session ends, the Stop hook scores it by friction — signals that the session hit something worth remembering: you interrupted or corrected the AI, denied a tool call, or the AI had to retry failing tools. A long-but-routine session (lots of tool calls, no friction) does not trigger; a session where you actually fought a problem does. If the score is high enough, the AI suggests:
[teamai] This session may contain a problem worth documenting: you interrupted the AI twice, the AI retried failing tools 8 times.
Task: Fix duplicate project-level Hook injection
Consider running `/teamai share what this session taught me` to summarize what you learned and share it with your team (or run `teamai skill get share`).
The hint names the non-zero friction signals that triggered it and, when available, includes a redacted, single-line summary of the first task. The share workflow (teamai skill get share) summarizes the session and pushes a learning document directly to the team repo. Each session is prompted at most once. Teams can switch the hint off with sharing.contributeHint.enabled: false in teamai.yaml (members: contributeHintEnabled in local config) while keeping the rest of the Stop hook. The hint also needs recall to be on (it is off by default), because the workflow it points at is served only then. For the same reason it never appears on a read-only HTTP source or while a teamai config exists but cannot be loaded, and it never appears in a directory where teamai is not set up.
Team Knowledge Recall
Let the AI automatically search accumulated team knowledge before a task. This feature is off by default and must be enabled explicitly — teams can set sharing.recall.enabled: true in teamai.yaml as the default, and members can override locally:
teamai recall enable # on: deploy the teamai-recall subagent + inject guidance rules
teamai recall disable # off: remove the subagent and rules
teamai recall status # show effective state (team default + user override)
Search runs via a subagent: once enabled, teamai pull deploys the built-in teamai-recall subagent into each AI tool's agents/ directory. The AI invokes it before a task — the subagent extracts keywords, runs the search, reads the matched source files, and returns a structured summary of team knowledge. The subagent first runs a relevance precheck (teamai recall --check) and skips retrieval entirely when the task is unrelated to team knowledge. Under the hood it shells out to the teamai recall command, which you can also run manually:
$ teamai recall "port conflict"
[1/2] MR review caught a port-conflict bug ★1 [user]
Author: member-a | Score: 18.5 | Tags: troubleshooting, networking
[2/2] Deployment configuration best practices [project]
Author: member-b | Score: 12.0 | Tags: deploy, config
Matched: conflict | Missing: port
Codebase Knowledge Graph
teamai import parses source repos into a structured graph under teamwiki/, enabling structurally-aware retrieval:
teamai import --from-repo https://github.com/org/repo
teamai import --from-org myorg # batch import all repos
teamai codebase --extract /path/to/repo # local extract into teamwiki/
teamai codebase --deep-enrich --project my-service --output /path/to/repo # generate deep knowledge docs
teamai codebase --reconcile --output /path/to/repo # map product docs to code pages
teamai codebase --lint --output /path/to/repo # check the locally extracted graph
Extract writes teamwiki/evidence/code/<project>/_manifest.json even when AI enrichment is skipped or produces nothing, so --deep-enrich can start.
The graph stores components, interfaces, configs, and cross-repo import edges. teamai recall uses it for graph-boosted re-ranking.
When a recall hit comes from a codebase page, the result includes a Sources: line listing the relevant source file paths — giving agents a direct starting point for code changes instead of re-exploring the repo.
Edges come from two tracks that run together, with AST results taking precedence on overlap:
- AST track (TypeScript/JavaScript, Python, Go): a WASM tree-sitter parser resolves
import/require, call sites, and TSimplementsclauses to precise file-to-fileDEPENDS_ON/REFERENCES/IMPLEMENTSedges (taggedcode-ast, with confidence weights). - Heuristic track (all languages, including Java/Rust): regex-based extraction (tagged
code-heuristic), which also covers languages the AST track does not.
The WASM parser is a pure-JavaScript dependency — no native toolchain is required. If it fails to load for any reason, extraction falls back to the heuristic track and records an AST_UNAVAILABLE gap. Set TEAMAI_SKIP_AST=1 to force heuristic-only extraction.
Team Improvement (beta)
Every execution makes the entire team smarter.
Maintenance
As skills and knowledge accumulate, prune what the team no longer uses. teamai recall maintenance archives low-confidence learnings and flags stale skills, rules, and docs for cleanup or updates:
teamai recall maintenance --prune --dry-run # preview
teamai recall maintenance --prune --archive # archive unused learnings
teamai recall maintenance --update-quality # draft updates for stale skills / docs
Insight into how the team actually uses its AI tools, and a starting point for turning session friction into shared skills, rules, and knowledge:
| Capability | Command | What it shows |
|---|---|---|
| Usage | teamai digest |
Weekly team digest — 7-day success, prompt, active-time, estimated cost, cache, and correction trends, plus lifetime totals. |
| Sessions | teamai session save |
Privacy-scrubbed per-session summaries (tool sequence, prompt turns, interventions) that feed the digest's Session Highlights. |
| Dashboard | teamai dashboard |
Unified Overview / Team Execution / Team Context / Team Improvement views with local live sessions, 7-day trends, estimated cost per session, English/Chinese, and light/dark/system themes. |
| KB Health | teamai dashboard → Team Context / Team Improvement |
Coverage by type, top-recalled and silent entries, last-recall month distribution, author contributions, and maintenance; the full /kb-report remains available. |