[feat] Read every member setting in one order: environment, this scope, this machine, the team
Maintainers usually reply within 1 day
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 20/100
- Issue type
- Feature
- Clarity
- Clearly specified
- Activity status
- Stale
- Tech stack
- typescript, yaml
- Domain
- cli
Research direction
The issue names the main entry points in src/config.ts, including LocalConfigSchema, resolveConfigForDir, refreshRoleAssignment, and serializeLocalConfig, plus the listed readers in src/tool-launch/call.ts, src/workflow-commands.ts, src/workflow/drivers/local/local-driver.ts, src/hook-handlers.ts, src/local-agent.ts, and src/doctor.ts. Start by reading the config loading and role overlay paths, then trace the named readers and existing tests for them. Done means member settings resolve in the specified order, saves preserve only scope-owned values, and doctor reports which level set each value; linked PR #1477 is already open.
Written by the indexing model from the issue text.
Description
Example
A member set up two workspaces with the default teamai init and never installed user scope. Today they cannot set anything for the whole machine. The docs send them to ~/.teamai/config.yaml. With a file that holds only settings, every command prints ✖ Invalid local config: repo: Required; username: Required (7 times on status, 29 on doctor), and the settings do nothing. With a user install as well, most readers in a workspace still ignore that file, because they read the workspace's own config.yaml.
After this issue, the member writes the machine file and overrides it in one workspace:
# ~/.teamai/config.yaml: this machine. No repo or username needed
ai:
tool: codex
recallEnabled: true
workflows:
tools: { default: codex }
# ~/.teamai/projects/<slug>/config.yaml: the workspace ~/work/a
ai:
tool: claude
recallEnabled: false
$ cd ~/work/a && teamai doctor
…
ℹ Member settings:
ai.tool: claude, from the workspace config ~/.teamai/projects/<slug>/config.yaml
recallEnabled: false, from the workspace config ~/.teamai/projects/<slug>/config.yaml (the machine says true, the team false)
workflows.tools.default: codex, from the machine config ~/.teamai/config.yaml
$ cd ~/work/b && teamai import --dir . # runs on codex, from the machine config
What changes
Each member setting is read in this order. The first level that sets it wins:
1. environment or flag where the key has one (TEAMAI_AI_TOOL, --tools, …), at the places that read it today
2. this scope the config.yaml of the scope the command runs in (workspace, self or user)
3. this machine ~/.teamai/config.yaml
4. the team teamai.yaml of this scope's team, where a team key exists
5. default
In user scope, levels 2 and 3 are the same file. Levels 1, 4 and 5 stay where they are today, in each key's resolver (isRecallEnabled, isContributeHintEnabled, resolveCoAuthor, … in src/types.ts:282-360) and at the flags. This issue adds level 3 below a workspace or self scope, and level 2 where a reader skips it.
| Key | 1 env or flag | 2 this scope | 3 this machine | 4 team |
|---|---|---|---|---|
ai.tool (#1444) |
TEAMAI_AI_TOOL |
yes (#1444) | yes | - |
workflows.tools.<agent>, workflows.max_parallel, workflows.auto_approve, workflows.sandbox, workflows.allow.<key> |
--tools, --auto-approve |
yes | new | - |
recallEnabled |
TEAMAI_RECALL_DISABLED (hooks) |
yes | new | sharing.recall.enabled |
contributeHintEnabled |
TEAMAI_CONTRIBUTE_HINT_DISABLED |
yes | new | sharing.contributeHint.enabled |
mrHintEnabled |
TEAMAI_MR_HINT_DISABLED |
yes | new | sharing.mrHint.enabled |
coAuthorEnabled |
- | yes | new | sharing.coAuthor.enabled |
usageReportEnabled |
- | yes | new | usageReport |
codexTrustEnabled |
- | yes | new | - |
modelAliases.<alias> |
- | new | yes | - |
updatePolicy, autoCompactTokens |
- | see below | new | autoUpdate, sharing.autoCompact.tokens |
A key is a path to one value. In a map (workflows.tools, workflows.allow, modelAliases) each entry is a key of its own, so a workspace that sets workflows.tools.implementer still takes workflows.tools.default from the machine.
updatePolicy and autoCompactTokens act on what the whole machine shares: the installed CLI, and each tool's own config file. One scope decides them: the user scope when its config can be read, else the scope that runs. #1456 makes both readers follow that rule. This issue adds only level 3 when no user scope is installed. A team's autoUpdate: false or sharing.autoCompact.tokens therefore holds on a member's machine only when that team's scope decides.
updatePolicy from the machine file takes effect once #1456 is fixed, since doUpdate reads only ~/.teamai/config.yaml as an install today.
toolRoots keeps its own rule: this scope, else this machine, as a whole map (resolveMemberToolRoots, src/config.ts:609-617), and init still copies it into a new workspace config (src/init.ts:812-815).
One declaration, one overlay
The member settings above are declared once, as a schema of their own composed into LocalConfigSchema (src/types.ts:810). Every other key of LocalConfigSchema is outside this overlay: repo, username, scope, projectRoot, provider, primaryRole, additionalRoles, projects, subscribedTags, excludedSkills, enabledAgents, disabledAgents, inheritUserScope, resourceProfileVersion, gitExcludeEnabled (one checkout's .git/info/exclude, #915), toolRoots (its own rule, above), and scoring (per data home: a machine value would start paid session judging in every workspace). A test fails when a key of LocalConfigSchema is in neither list.
One function reads the machine settings from ~/.teamai/config.yaml, whether or not that file is an install. The overlay fills its values into a workspace or self config wherever the team's role assignment is applied today (#1186): when a partition config is loaded (src/config.ts:437, :759), and in refreshRoleAssignment (src/config.ts:188), which init and pull run on a config they built or hold in memory (src/init.ts:798, :1415, :2310, src/pull.ts:1433). A load runs it more than once, so applying it twice gives the same config, as the role overlay's guard does (src/config.ts:116-119). So init's first hook reconciliation, on the git, self and HTTP paths alike, already sees a machine codexTrustEnabled: false, and every reader that takes a LocalConfig gets the resolved value without a change of its own.
Saving must not copy a machine value into the scope's file, and must keep what a command set. The overlay keeps the machine values it applied, runtime-only. serializeLocalConfig (src/config.ts:304) leaves out a key while it still holds the applied value, unless a command set it. recall enable and recall disable (src/recall-toggle.ts:107, :122), the only commands that write a member setting, mark the key as set, so recall disable in a workspace persists recallEnabled: false even when the machine already says false.
The readers that read ~/.teamai/config.yaml directly change as follows:
| Reader (#1444 unless noted) | Today | After |
|---|---|---|
callTool (src/tool-launch/call.ts:85) |
done in #1444: aiToolSettings (src/config.ts) reads ai.tool from the scope config, then the machine file; the overlay replaces that reader |
resolveConfigForDir(process.cwd()) by default, since no caller holds a config today; a caller acting for another scope passes its config. With no scope, the machine settings; a scope config that cannot be read, or a repository git cannot read, is an error, not a fallback (resolveConfigForDir returns nothing in all three cases, and only its onUnreadable callback tells them apart, src/config.ts:579-597). The per-process pick cache (call.ts:97-98) is keyed by the resolved ai.tool |
workflow start (src/workflow-commands.ts:172) and the local driver (src/workflow/drivers/local/local-driver.ts:336) |
done in #1444 for ai.tool, through aiToolSettings; workflows.* still loadLocalConfig() |
the config the workflow already selected (readyStartConfig, runOwner, src/workflow-commands.ts:104-125) |
price-table aliases (src/hook-handlers.ts:440-449, main) |
loadLocalConfig() |
the config the hook dispatcher resolved |
the HTTP local agent's Codex trust (src/local-agent.ts:582, :588, main) |
loadLocalConfig(); the agent has no scope config |
the machine settings |
ci extract-mr keeps running with no teamai init (#1389): with no scope and no machine file, every key is at its default.
A missing or partial machine file
~/.teamai/config.yaml |
User scope | Level 3 |
|---|---|---|
| missing | not installed | empty |
no repo key |
not installed. Today this is the "could not be read" path (src/config.ts:388-396) and logs Invalid local config on every load. After, it is "not initialized", with no error |
its member settings |
| an install | installed, as today | its member settings |
| an install that does not validate | not usable, as today: The teamai config at … could not be read |
its member settings that validate |
Level 3 reads each member setting on its own, from the file as YAML. A value of the wrong type (recallEnabled: "yes") is skipped, the next level decides, and each command that reads it warns once: recallEnabled in ~/.teamai/config.yaml is "yes", not true or false, so it is ignored. That is how scorers/scoring.yaml treats a bad key (src/scorers/settings.ts:39-79). workflows.allow is the exception: a bad value there fails the workflow command and names the key, so a typo never lifts a restriction. A key in a settings-only file that is not a member setting (excludedSkills, …) is not read, and doctor says so. In a scope's own config, a bad value still makes that config unreadable, as today, because that file is also the install record.
Whether user scope is installed is one exported check, used everywhere it is asked: ~/.teamai/config.yaml holds a repo key. #1444 added that check as hasUserScopeInstall (src/config.ts:300) and already uses it in throwMissingOrInvalid, the env loader's user row, Hermes' global rules and init's re-init guard, owner check and set-aside recovery; both loaders that print Invalid local config stay silent for the same files. Its rule is narrower: a file holding only member-setting keys (MEMBER_SETTING_KEYS, today only ai) is not an install. This issue widens that rule to "no repo key" rather than adding a second check. An install that fails validation still has its repo key, so it still counts as installed, as rules.ts:967 wants.
init --scope user (git or --http) over a settings-only file takes the machine settings as the new config's own values, beside what it carries today (carriedConfig, src/init.ts:1689-1691), before its first hook reconciliation, with no "already initialized" prompt. Today it stops with teamai is already initialized for user scope, and with --force moves the file to config.yaml.previous as another install's config.
Which level won
doctor and doctor --json add Member settings: each member setting set at any level, with its value, the level and file (or variable) that set it, and the values of the levels below it, the team's included. In user scope the file is named once, as "the user config, also this machine's". For updatePolicy and autoCompactTokens it shows the value of the scope that decides, and says when this scope's own value is not used. Text that already names a file for a setting's value names the level that set it instead: #1444's ai.tool error (src/tool-launch/call.ts:71, :77) and doctor's usage-reporting note (src/doctor.ts:516), which today name ~/.teamai/config.yaml and the scope's own config.yaml whatever set the value.
Out of scope
- A team default or per-namespace default for keys that have no team key today (
ai.tool,workflows.*,codexTrustEnabled). No team has asked, and level 4 has room for one later. - Per-namespace values for the existing team keys.
scorers/<ns>/scoring.yamlstays the only per-namespace setting file. - The install keys listed above,
scoring.*included. - A command to set these keys. Members edit the files, as the docs say today.
- Env and secret values per workspace (#1429).
- Bugs filed on their own: #1456 (which scope decides
updatePolicyandautoCompactTokens), #1457 (TEAMAI_RECALL_DISABLEDnot stoppingpull) and #1458 (init --forcedropping member settings; its fix carries the scope file's own values, never overlaid ones). The docs that send members to~/.teamai/config.yamlfor keys a workspace reads from its own config are fixed here (Definition of done). uninstall. A user-scope uninstall that removes~/.teamai/config.yamltakes the machine settings with it, as today.
Acceptance
- In a workspace-only install,
~/.teamai/config.yamlholding onlyai: { tool: codex }makesimport --dir,recall promote, and aworkflow start --driver localprompt step with noworkflows.toolsentry run on codex.status,doctorandpullprint noInvalid local configand no warning about the user scope, and the env registry gets no user row. - With no install at all, the same file makes
teamai ci extract-mrin a bare checkout run on codex (the one AI command that runs withoutteamai init). - With
ai.tool: claudein that workspace's config as well, those run on claude there and on codex in another workspace. - With user and workspace installs,
recallEnabled: truein~/.teamai/config.yamlturns recall on in a workspace whose config does not set it.recall disablein that workspace writesrecallEnabled: falseto its config, and a laterpullkeeps recall off. - A save by any other command leaves the workspace config without the machine's settings.
codexTrustEnabled: falsein a settings-only machine file stopsinitof a new workspace from trusting its Codex hooks.recall disablein a workspace whose machine file already saysrecallEnabled: falsestill writes the key to the workspace config.codexTrustEnabled: falsein a settings-only machine file stopsinit --httpfrom trusting the local agent's Codex hooks.- A bad value at level 3 is warned about, and the next level decides. A bad
workflows.allowvalue fails the workflow command. init --scope userover a settings-only file, with no TTY and no--force, installs user scope and keeps the file's member settings.doctorlists each member setting with its level, file and the levels below. WithusageReportEnabled: falseonly in the machine file, its usage-reporting note names the machine file.- A key added to
LocalConfigSchemafails a test until it is declared a member setting or an install key.
Definition of done
- Docs, English and
zh-CN:docs/guide/reference.md(the config section explains the levels and lists the member settings), and the lines that name a file for a key:knowledge.md:38,:82,:92,member-guide.md:117,:140,diagnostics.md:28-36,reporting.md:14-18,workflow.md:154,workflow-advanced.md:57,:620. Grep~/.teamai/config.yamland "local config" before the PR. CHANGELOG.md,### Changed: member settings in~/.teamai/config.yamlnow apply in every workspace and self scope whose own config does not set them, also for workspaces of other teams.updatePolicyandautoCompactTokensfollow the deciding-scope rule above. A member with a user install who set one there, for examplerecallEnabled,coAuthorEnabled,usageReportEnabledorworkflows.*, for user scope only sees it apply in their workspaces too.- Real-CLI record: a workspace-only install with a settings-only machine file, showing
doctor'sMember settingsand one AI call on the machine's tool; then the workspace override; thenrecall disableand apull.
- Dominant language
- TypeScript
- Stars
- 5.6k
- Forks
- 471
- Avg merge
- 19h 39m
- Merged PRs (30d)
- 404
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
-
[feat] deep-enrich: compare the G documents with the wiki method, then write what is missingPossibly taken @huong8373tt-beep claimed this today. Open
Difficulty 5/5 Over a week Newbie friendliness 42/100
Tencent/teamai-cli#1565 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 20/100
Tencent/teamai-cli#1564 ·
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 35/100
Tencent/teamai-cli#1563 ·
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 35/100
Tencent/teamai-cli#1562 ·
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 20/100
Tencent/teamai-cli#1552 · 1 comment ·
Maintainers usually reply within 1 day
All issues in Tencent/teamai-cli
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
area:web p3
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Lets-Parley/Parley#912 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
wealthfolio/wealthfolio#2376 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
be-BOP-io-SA/be-BOP#2817 ·
Maintainers usually reply within 5 days
-
documentation good first issue
Difficulty 1/5 1-3 hours Newbie friendliness 84/100
sno-ai/sno-station#149 · 1 comment ·
Maintainers usually reply within 1 day