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

[feat] Read every member setting in one order: environment, this scope, this machine, the team

Closed
#1,459 4 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

@hz89Dev is already working on this.

Since Oct 28, 2026.

  • #1535 by @hz89Dev — open

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

enhancement

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.yaml stays 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 updatePolicy and autoCompactTokens), #1457 (TEAMAI_RECALL_DISABLED not stopping pull) and #1458 (init --force dropping member settings; its fix carries the scope file's own values, never overlaid ones). The docs that send members to ~/.teamai/config.yaml for keys a workspace reads from its own config are fixed here (Definition of done).
  • uninstall. A user-scope uninstall that removes ~/.teamai/config.yaml takes the machine settings with it, as today.

Acceptance

  • In a workspace-only install, ~/.teamai/config.yaml holding only ai: { tool: codex } makes import --dir, recall promote, and a workflow start --driver local prompt step with no workflows.tools entry run on codex. status, doctor and pull print no Invalid local config and 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-mr in a bare checkout run on codex (the one AI command that runs without teamai init).
  • With ai.tool: claude in that workspace's config as well, those run on claude there and on codex in another workspace.
  • With user and workspace installs, recallEnabled: true in ~/.teamai/config.yaml turns recall on in a workspace whose config does not set it. recall disable in that workspace writes recallEnabled: false to its config, and a later pull keeps recall off.
  • A save by any other command leaves the workspace config without the machine's settings.
  • codexTrustEnabled: false in a settings-only machine file stops init of a new workspace from trusting its Codex hooks.
  • recall disable in a workspace whose machine file already says recallEnabled: false still writes the key to the workspace config.
  • codexTrustEnabled: false in a settings-only machine file stops init --http from trusting the local agent's Codex hooks.
  • A bad value at level 3 is warned about, and the next level decides. A bad workflows.allow value fails the workflow command.
  • init --scope user over a settings-only file, with no TTY and no --force, installs user scope and keeps the file's member settings.
  • doctor lists each member setting with its level, file and the levels below. With usageReportEnabled: false only in the machine file, its usage-reporting note names the machine file.
  • A key added to LocalConfigSchema fails 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.yaml and "local config" before the PR.
  • CHANGELOG.md, ### Changed: member settings in ~/.teamai/config.yaml now apply in every workspace and self scope whose own config does not set them, also for workspaces of other teams. updatePolicy and autoCompactTokens follow the deciding-scope rule above. A member with a user install who set one there, for example recallEnabled, coAuthorEnabled, usageReportEnabled or workflows.*, 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's Member settings and one AI call on the machine's tool; then the workspace override; then recall disable and a pull.
Dominant language
TypeScript
Stars
5.6k
Forks
471
Avg merge
19h 39m
Merged PRs (30d)
404

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.