Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
2f3b2e4
feat(recall): tune promotion thresholds by replacing the promote work…
Walternater Nov 12, 2026
8f50c3b
fix(recall): surface invalid promotion gates in the dashboard
Walternater Nov 12, 2026
07dbd01
docs: say two members can see different promotion gates
Walternater Nov 12, 2026
3ed50c1
feat(hooks)!: keep a default hook's parameters in params.yaml
SaulMoro Nov 12, 2026
95665ca
refactor(defaults): one contract for the default folders code reads
SaulMoro Nov 12, 2026
d207515
docs(changelog): describe default hook parameters once
SaulMoro Nov 12, 2026
b276047
feat(recall)!: tune promotion gates in the promote workflow's params.…
SaulMoro Nov 12, 2026
f1da753
feat(recall): tune which entries --update-quality drafts in params.yaml
SaulMoro Nov 12, 2026
2ec0dcf
refactor(duration): read a duration without the workflow parser
SaulMoro Nov 12, 2026
73e80ac
feat(sessions): set when a session is finished in params.yaml
SaulMoro Nov 12, 2026
a47b97c
feat(hooks): word the friction reminder's reasons as texts of its folder
SaulMoro Nov 12, 2026
1745b5a
feat(codebase): set how many docs --deep-enrich writes at once in par…
SaulMoro Nov 12, 2026
9a17209
docs(workflows): describe a default folder replaced one file at a time
SaulMoro Nov 12, 2026
468a2c6
test(hooks): a team reason text reads {{ count }}
SaulMoro Nov 12, 2026
8221941
fix(hooks): word a reason by the language of the file read, not the t…
SaulMoro Nov 12, 2026
ba13eee
fix(codebase): read deep-enrich concurrency from the member's scope f…
SaulMoro Nov 12, 2026
1f3b1eb
fix(recall): read the dashboard's maintenance gates only from a scope
SaulMoro Nov 12, 2026
29bf331
docs(changelog): record moving default hook parameters out of with: a…
SaulMoro Nov 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion CHANGELOG.md

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions docs/dev/glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ _Avoid_: level, source, scope (that is a **scope**)
A **resource** teamai ships, named `teamai-<name>`. A team replaces it, or some of its files, with a folder of the same name at the **team root**. Short form: default, as in default workflow or default scorer.
_Avoid_: built-in, shipped, preset

**Default parameters**:
The values of a **teamai default** a team may tune, in `params.yaml` of its **resource folder**. Read the same everywhere the default's code runs, inside a workflow run or outside one, and set for the whole team, unlike a workflow input, which one run sets. A team's `params.yaml` sets only the keys it changes; every other key keeps teamai's value.
_Avoid_: settings, config, `with:` (a step's inputs to another workflow)

**Team root**:
The top of the **team repo**, outside any namespace.
_Avoid_: repo root (ambiguous with the **workspace**'s own repo)
Expand Down
2 changes: 1 addition & 1 deletion docs/dev/tool-launch.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Each rule below spans more than one file. The rule names the code that owns it,
## How a feature asks an AI tool

It writes an `answer` step in its default workflow. This is the step `recall maintenance --update-quality` runs, from
`workflows/teamai-draft-learning-updates.yaml`:
`workflows/teamai-draft-learning-updates/WORKFLOW.yaml`:

```yaml
- id: ask
Expand Down
2 changes: 1 addition & 1 deletion docs/dev/workflow-engine.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ A default whose scorer is asked once per item of a session (a delivered skill, a
- **A fallback reads why a step failed, never only that it failed.** `currentStep` in `scope.ts` gives a settled step's `failure` (code and message, current pass only) to expressions and templates; `stepFieldSchema` in `expression.ts` types it, and `undeclaredField` in `parse-context.ts` refuses a field it lacks. A migrated default that kept a success-shaped fallback guards it on the code, and ends the run `failed` on a code the fallback must not hide, such as `tool_unconfigured` for a tool the member names that cannot run: `continue_on_failure` alone would let the run succeed with nothing done. A command that exits `INPUT_REJECTED_EXIT` (65) fails `input_rejected`, and one that exits any other non-zero status fails `command_failed` (`commandEnd` in `protocol.ts`), so a failed command step's `failure` is never null. `explainFailedSteps` in `workflow-commands.ts` offers no retry for `input_rejected`, and says `command_failed` by its message alone, which names the status. Under a shortcut, whose progress already showed a command's stderr, it names a failed command step by its exit status only, so each message is said once.

```yaml fragment
# workflows/teamai-promote-learning.yaml, abridged
# workflows/teamai-promote-learning/WORKFLOW.yaml, abridged
ends: { unconfigured-tool: failed }
steps:
- id: content
Expand Down
4 changes: 2 additions & 2 deletions docs/guide/dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ teamai-recall rules/teamai-recall/ Team root Folder Refused
rules/teamai-recall/ is not used, so teamai's recall rule stays in force: rules/teamai-recall/RULE.md does not contain "Nothing was searched:". Fix the folder in the team repo.
```

Rule files stay on the rule list above. Default hooks lists teamai's five hints: where each comes from, how many `with:` parameters and texts the team's folder changes, and, opened, each parameter's teamai and team value, the changed ones marked, and the file each text is read from for the team's language.
Rule files stay on the rule list above. Default hooks lists teamai's five hints: where each comes from, how many parameters and texts the team's folder changes, and, opened, each parameter's teamai and team value, the changed ones marked, and the file each text is read from for the team's language.

The Overview counts the problems and links here:

Expand Down Expand Up @@ -399,7 +399,7 @@ curl -s 'http://localhost:3721/api/tokens?days=30' | jq -r '.byModel[] | select(

The Overview's **What finished sessions delivered** panel shows the sessions the usage report counted in the last 30 days for the selected workspace: the share that delivered a commit, pull request or learning, the rows per run mode and outcome with tokens and interventions per session (see [Usage reporting](reporting.md#what-your-sessions-delivered)), and the latest sessions with their commits, pull request links and learnings.

A session row and its details show the learnings `teamai contribute` recorded for it. Its commits and pull request are counted 6 hours after it goes quiet, after the row has left the list, so they show in the panel. These ids, shas and links stay on this machine.
A session row and its details show the learnings `teamai contribute` recorded for it. Its commits and pull request are counted once it has been quiet for the [`idle` of `teamai-finished-sessions`](scorers.md#teamai-finished-sessions), 6 hours unless the team changed it, after the row has left the list, so they show in the panel. These ids, shas and links stay on this machine.

## Session Save

Expand Down
4 changes: 2 additions & 2 deletions docs/guide/knowledge.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ teamai recall maintenance --prune --archive
teamai recall maintenance --update-quality
```

`--archive` puts aside learnings whose confidence is below 0.15. `--update-quality` writes a `.draft.md` beside each entry the team recalls often but rarely adopts. Rename it to `.md` when the draft is right; until then `teamai pull` delivers none of it. It runs the default workflow [`teamai-draft-learning-updates`](workflow.md#default-workflows), and exits 1 when an entry could not be drafted.
`--archive` puts aside learnings whose confidence is below 0.15. `--update-quality` writes a `.draft.md` beside each entry the team recalls often but rarely adopts. Rename it to `.md` when the draft is right; until then `teamai pull` delivers none of it. It runs the default workflow [`teamai-draft-learning-updates`](workflow.md#default-workflows), and exits 1 when an entry could not be drafted. By default an entry is drafted when members recalled it at least 5 times in all, at least 2 of them, and upvoted it at most once; a team changes that in `workflows/teamai-draft-learning-updates/params.yaml`, which its [README](https://github.com/Tencent/teamai-cli/blob/main/workflows/teamai-draft-learning-updates/README.md) describes.

Digest and maintenance commands (`teamai digest`, `teamai recall maintenance`, and `teamai recall promote`) include the active learnings namespaces for the current scope alongside the shared root.

Expand All @@ -205,7 +205,7 @@ Confidence is an activity score from 0 to 1, not a probability that the knowledg

### Promoting Learnings

A learning can become a skill, rule, or doc when its confidence is at least 0.90, it has at least 5 upvotes, at least 2 contributors, and it has existed for at least 14 days.
A learning can become a skill, rule, or doc when its confidence is at least 0.90, it has at least 5 upvotes, at least 2 contributors, and it has existed for at least 14 days. A team changes these in a `params.yaml` of `workflows/teamai-promote-learning/` at the root of its repo, holding only the keys it changes, such as `min_users: 1`; the [workflow's README](https://github.com/Tencent/teamai-cli/blob/main/workflows/teamai-promote-learning/README.md) lists them and their ranges. Members on a teamai older than the one that reads it keep the old gates, so upgrade every member first.

Promoted skills use `skills/<learningId>/SKILL.md`, with missing `name` and `description` frontmatter filled in so tools can discover them. Rules and docs remain Markdown files in their respective directories.

Expand Down
2 changes: 1 addition & 1 deletion docs/guide/reporting.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ unattended:

### What your sessions delivered

A session of yours is added to `outcomes`, by its run mode and by what it delivered, by the next report once it has been idle for 6 hours. An unattended session is also added by the `teamai score --drain` that ends its job, so an ephemeral runner reports its sessions:
A session of yours is added to `outcomes`, by its run mode and by what it delivered, by the next report once it has been idle for the [`idle` of `teamai-finished-sessions`](scorers.md#teamai-finished-sessions), 6 hours unless the team changed it. An unattended session is also added by the `teamai score --drain` that ends its job, so an ephemeral runner reports its sessions:

```yaml
outcomes:
Expand Down
10 changes: 5 additions & 5 deletions docs/guide/scorers.md
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,7 @@ daily_limit: 10 # per data home: on a fresh CI
|---|---|---|
| `off` | Nothing. The default. | Nothing. |
| `ask` | When the friction reminder offers [`teamai-share-learnings`](workflow.md#teamai-share-learnings-and-teamai-share-session), it proposes the scorers that sample the session, and they judge it once the person confirms. | Acts as `off`, since nobody is there to answer. |
| `auto` | A session is judged once nothing has happened in it for six hours, by the [`teamai-finished-sessions`](#teamai-finished-sessions) run a session start begins. | A session is judged when `teamai score --drain` runs, before the job ends. The default. |
| `auto` | A session is judged once nothing has happened in it for six hours, or the `idle` the team sets, by the [`teamai-finished-sessions`](#teamai-finished-sessions) run a session start begins. | A session is judged when `teamai score --drain` runs, before the job ends. The default. |

Each mode resolves on its own, from the first of these that sets it: a member's `scoring.sessions` in `config.yaml`, the active namespaces' `scoring.yaml` files, the root `scorers/scoring.yaml`, the default. When two active namespaces disagree, the most restrictive policy wins (`off`, then `ask`, then `auto`), and so does the lowest `daily_limit`. A partial mapping such as `{ attended: ask }` leaves the other mode to the next level:

Expand Down Expand Up @@ -732,7 +732,7 @@ The rubric is the [default scorer](#default-scorers) `scorers/teamai-adoption.md

```text
teamai-finished-sessions private, invoke: deny, timeout 30m
sessions teamai session list --finished --idle 6h the finished sessions to archive or judge here
sessions teamai session list --finished the finished sessions to archive or judge here
share teamai-share-session, for each its publish step, then its teamai-score step
lapsed teamai score subjects --lapsed passes and sessions whose judging lapsed, and passes no run scored, each with its scorers
rescore teamai-score, for each starts their judging again with those scorers only
Expand All @@ -748,12 +748,12 @@ $ teamai workflow start teamai-finished-sessions --driver local --inputs '{"publ

| Clock | Set in | Default |
|---|---|---|
| A session counts as finished | `--idle` of the `sessions` step | 6 hours after its last activity; an unattended session once a drain reached it |
| A session counts as finished | `idle` of the folder's `params.yaml` | 6 hours after its last activity; an unattended session once a drain reached it |
| A run ends | the file's `timeout` | 30 minutes; what it cancels lapses, and the next run starts it again |
| A judge no driver here takes | the `timeout` of share-session's `score` step | 30 minutes; the session stays published and its judging lapses |
| A lapse is started again | the scoring marks | until the fourth lapse, and only within 14 days of the run's last change; with the scorers its marks hold, a named one included, unsampled and, once named, never refused by `daily_limit`, and with no scorer the session policy would add now |

A team changes these in `workflows/teamai-finished-sessions.yaml` in its team repo, which replaces the default: `--idle 1h` takes a session one hour after its last activity, and `timeout` bounds a run. Steps can be added or reordered there too. What a team cannot change stays in the CLI: the automatic starts pass no agent evidence and only the policy inputs.
A team changes the idle time with `workflows/teamai-finished-sessions/params.yaml` in its team repo, holding `idle: 1h` to take a session one hour after its last activity, from `10m` to `7d`. The dashboard, the session sharing proposals and the usage report's outcomes count a session finished at the same time. A `WORKFLOW.yaml` of its own in that folder changes the steps and their `timeout`, and steps can be added or reordered there too; the folder's [README](https://github.com/Tencent/teamai-cli/blob/main/workflows/teamai-finished-sessions/README.md) lists what it keeps. What a team cannot change stays in the CLI: the automatic starts pass no agent evidence and only the policy inputs.

### Drain before an unattended job ends

Expand All @@ -768,7 +768,7 @@ $ teamai score --drain

Every unattended driver ends with `teamai score --drain`. The local driver runs it at the end of an unattended run, unless publishing and scoring of unattended sessions are both `off`, or the run is a `teamai-finished-sessions` run. The skill driver, T3, Paseo and a CI script run it as their last step. It works in this order:

1. In unattended mode, every session this data home captured as unattended counts as finished, the calling session included. Attended sessions keep the six-hour rule.
1. In unattended mode, every session this data home captured as unattended counts as finished, the calling session included. Attended sessions keep the idle rule, six hours unless the team changed it.
2. It starts a [`teamai-finished-sessions`](#teamai-finished-sessions) run here, as a session start does, and drives it on the driver `workflows.driver` names, else on the local driver. A run for a driver this machine does not run waits for it, and the drain says how to drive it here. The run archives the finished sessions with `publish: auto` for their mode and judges the sampled ones the policies allow, within `daily_limit`. It starts `teamai-score` again for each pass and session whose judging lapsed, for each `start: workflow` pass its run left unscored, and for the open passes and sessions the upgrade carried over from judge attempts, except a pass whose run last changed more than 14 days ago. A run already working on this data home is left to it, and the drain says so: run the drain again once it ends.
3. It publishes every pending label, and what a [`deliver: publish`](workflow.md#publish-to-a-data-branch) step left pending on a data branch, as `score --push` does, and the workflow run records a run could not publish, as `teamai pull` does.
4. With `publish: auto` for the current mode, it archives on `teamai-reports`, scrubbed, the step sessions of the runs driven here that are not archived yet. A step session it cannot archive from here, because teamai reads no sessions from its tool or this machine cannot read it, is listed once as skipped with the reason, and never tried again. The other step sessions of that run are still archived. The trial sessions of a [benchmark](benchmarks.md) run stay on the machine that ran it.
Expand Down
14 changes: 6 additions & 8 deletions docs/guide/sharing.md
Original file line number Diff line number Diff line change
Expand Up @@ -506,13 +506,11 @@ agy then refuses the command with `tool call denied by pre-tool hook: rm -rf is

### Default hooks

teamai's own hints keep their thresholds and texts in hook folders. A folder of the same name at the root of the team repo changes one. Put in it only the files you change; every other file, `HOOK.yaml` included, stays teamai's and keeps getting teamai's updates. To remind only after longer sessions, in the team's words:
teamai's own hints keep their thresholds and texts in hook folders. A folder of the same name at the root of the team repo changes one. Put in it only the files you change; every other file stays teamai's and keeps getting teamai's updates. To remind only after longer sessions, in the team's words:

```yaml
# hooks/teamai-friction-reminder/HOOK.yaml
description: Remind after longer sessions only
with:
min_tools: 30
# hooks/teamai-friction-reminder/params.yaml
min_tools: 30
```

```markdown
Expand All @@ -530,7 +528,7 @@ After `teamai pull`, the reminder waits for 30 tool calls and opens with that li
| `teamai-env-hint` | The session-start note naming the scope's team env variables and secrets |
| `teamai-package-hint` | The session-start note that the team's package declarations changed |

- `HOOK.yaml` holds `description` and `with:`. A key left out of `with:` keeps teamai's value.
- `params.yaml` holds the parameters, and a key left out of it keeps teamai's value. `HOOK.yaml` holds only `description`.
- A text is `<text>.md`, with `{{ name }}` variables. With `language: en` or `zh`, `<text>.en.md` or `<text>.zh.md` is used when the folder has it.
- A text you write replaces all of teamai's languages of it: with your `problem.md` and no `problem.zh.md`, a `zh` team reads your `problem.md`. Write `problem.md` too when you write only one language.
- A file teamai's folder does not have replaces nothing. Pull warns, names it, and leaves it out. A misspelled `problems.md` shows up this way instead of silently doing nothing. When your folder has its own `HOOK.yaml`, it may add files.
Expand All @@ -540,7 +538,7 @@ After `teamai pull`, the reminder waits for 30 tool calls and opens with that li
Pull checks the folder your files and teamai's make together. It refuses one that sets a value out of range or a key the default does not take, reads a variable a text does not offer, lacks the base `<text>.md` of a text you wrote in one language, or has a `command`, and keeps teamai's folder in force:

```text
hooks/teamai-friction-reminder/ is refused, and teamai's default stays in force until it is fixed: HOOK.yaml: with.min_tools must be a whole number from 1 to 1000
hooks/teamai-friction-reminder/ is refused, and teamai's default stays in force until it is fixed: params.yaml: min_tools must be a whole number from 1 to 1000
```

A replacement replaces for the whole team, so pull refuses one in a namespace, such as `hooks/payments/teamai-friction-reminder/`. `teamai review --branch` fails a replacement pull refuses, or one with a file that replaces nothing, before you merge it.
Expand Down Expand Up @@ -768,7 +766,7 @@ sessions:
publish: { attended: ask, unattended: auto }
```

Attended `ask` proposes publishing when the friction reminder offers [`teamai-share-learnings`](workflow.md#teamai-share-learnings-and-teamai-share-session), and the person confirms it once, at the start. An agent that starts the run with `--confirmed` can confirm it for them, and teamai cannot check that they did. Otherwise a person's sessions are archived only by a command such as `teamai session push`. Unattended `ask` acts as `off`, since nobody is there to confirm. Attended `auto` archives a session once nothing has happened in it for six hours, in the [`teamai-finished-sessions`](scorers.md#teamai-finished-sessions) run a session start begins, which also judges finished sessions. A session pushed by hand before it finished is archived again once something happened in it after that push. Publishing always scrubs, which also rewrites local paths ([what a scrubbed session keeps](dashboard.md#what-a-scrubbed-session-keeps)). An HTTP team keeps no session archive, so there `sessions.publish` acts as `off`, and `teamai doctor` says so.
Attended `ask` proposes publishing when the friction reminder offers [`teamai-share-learnings`](workflow.md#teamai-share-learnings-and-teamai-share-session), and the person confirms it once, at the start. An agent that starts the run with `--confirmed` can confirm it for them, and teamai cannot check that they did. Otherwise a person's sessions are archived only by a command such as `teamai session push`. Unattended `ask` acts as `off`, since nobody is there to confirm. Attended `auto` archives a session once nothing has happened in it for six hours, or the `idle` the team sets, in the [`teamai-finished-sessions`](scorers.md#teamai-finished-sessions) run a session start begins, which also judges finished sessions. A session pushed by hand before it finished is archived again once something happened in it after that push. Publishing always scrubs, which also rewrites local paths ([what a scrubbed session keeps](dashboard.md#what-a-scrubbed-session-keeps)). An HTTP team keeps no session archive, so there `sessions.publish` acts as `off`, and `teamai doctor` says so.

A member's `config.yaml` wins, one mode at a time. A mode it does not name falls through to `teamai.yaml`:

Expand Down
Loading
Loading