{"owner":"larksuite","repo":"cli","hasSkills":true,"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md"],"skills":{"AGENTS.md":"# AGENTS.md\n\n## Purpose\n\n`lark-cli` is the official Lark/Feishu CLI for humans and AI agents. Optimize\nfor predictable machine-readable behavior without making the human CLI worse.\n\nKeep each PR focused on one goal: CLI UX, reliability, simpler explicit code,\nor a useful gate. Done means the correct implementation surface, preserved\ncontracts unless a break was requested, and reported checks.\n\nPublic behavior, tests, lint, and CI define current contracts. Existing code is\nevidence, but a legacy exception is not precedent; `Proposal` documents are\ndirection only. Do not mix unrelated cleanup, hand-edit generated files, weaken\ngates, or broaden allowlists to make CI pass.\n\n## Implementation Discipline\n\nUse this sequence for product behavior or enforcement changes:\n\n1. Establish the current contract and owner before choosing a solution. Trace the\n   flow from the command or shortcut through runtime and internal owners to wire\n   output; inspect affected callers and tests, then choose the surface below.\n2. Apply YAGNI to scope. Implement the behavior required now; do not add\n   speculative modes, configuration, compatibility paths, extension points, or\n   scaffolding.\n3. Reuse the project's existing machinery before creating a parallel path.\n   Prefer the owning generic, runtime, or internal surface, then the Go standard\n   library or an existing dependency, while preserving the contracts below.\n4. Fix the root cause at the narrowest cohesive boundary shared by affected\n   callers. Keep command and domain policy at the caller unless there is a real\n   cross-command invariant for an internal owner to enforce.\n5. Ship the smallest complete change: implementation, a revert-failing regression\n   test for behavior or enforcement, and required contract or guidance updates.\n\nOptimize for minimum owned complexity, not minimum diff or line count. A correct\nroot-cause fix may touch the owner, callers, tests, and docs; a one-line workaround\nat the wrong layer is not simpler. Prefer deletion and boring explicit code, and\navoid one-use abstractions or new dependencies for straightforward behavior.\n\nYAGNI never overrides explicit requirements or output, error, path, security,\ncompatibility, and data-safety contracts. If a deliberately limited solution has\na real ceiling, document the ceiling and the concrete condition for expanding it\nat the decision point.\n\n## Build\n\nRun `make build` for the canonical local build; it writes `./lark-cli` with\nversion metadata and the embedded service catalog. It, `make vet`,\n`make unit-test`, `make live-skills-test`, and dependent targets first run\n`python3 scripts/fetch_meta.py`, so Python 3 is required. On a clean checkout,\nthe ignored `internal/registry/meta_data.json` is absent and the first run needs\naccess to `open.feishu.cn`; a valid existing file is reused.\n`LARKSUITE_CLI_REMOTE_META=off` does not disable this build-time fetch.\n`make live-skills-test` requires working `npx` and network access.\n\nIf the fetch fails before Go starts, report the missing Python or network\nprerequisite instead of changing product code or generated metadata. `go build .`\nmay compile against the tracked empty fallback metadata, but that is only a\ndegraded compile check without the full service catalog.\n\n## Choose the Correct Surface\n\n| Need | Implement in | Rule |\n|------|--------------|------|\n| Agent/human-friendly workflow, composition, or smart defaults | `shortcuts/<domain>/` via `common.Shortcut` | Must add UX or workflow value beyond exposing one endpoint. |\n| One-to-one supported OpenAPI method | Upstream service metadata + generic `cmd/service/` machinery | Verify it with `schema` after the canonical metadata fetch. `internal/registry/meta_data.json` is generated and ignored; never hand-edit it or add a shortcut merely to expose a missing catalog method. |\n| Arbitrary OpenAPI endpoint | Generic `cmd/api/` machinery | Keep it endpoint-agnostic. |\n| Auth, config, profile, update, or CLI lifecycle | `cmd/<area>/` plus the owning shared/internal package | Keep new Cobra code as wiring when a lower owner exists. |\n| EventKey, payload shape, or domain projection | `events/<domain>/` | Shared event mechanics stay in `internal/event/`; CLI assembly stays in `cmd/event/`. |\n| Command-independent mechanism or cross-command invariant | Owning `internal/<area>/` package | Keep UX/domain policy at the caller; use a cohesive owner, not a generic utils package. Test the owner and affected caller contracts. |\n| Public plugin or host integration | `extension/` | Exported symbols are compatibility commitments; orchestration stays internal. |\n| Per-command decision guidance: when, avoid, prerequisites, tips, or examples | `affordance/<domain>.md` | Enrich `--help` and `schema` without restating command descriptions, flags, or field schemas. |\n| Domain routing, concepts, safety, or cross-command agent workflow | `skills/<name>/SKILL.md` and `references/` | Keep always-needed decisions in `SKILL.md`, conditional HOW in references, and link commands from affordance. |\n\nDo not duplicate one command surface inside another. Register new shortcuts in\nthe domain's `Shortcuts()`; declare risk, identities/scopes, flags, and dry-run.\n\n## Hard Contracts\n\nRead the [JSON output contract](README.md#json-output-contract) before changing\nwire output. Read the [source guard guide](lint/README.md) and `.golangci.yml`\nbefore changing or waiving enforcement.\n\n- Command/flag semantics, help/schema metadata, output placement and shapes,\n  errors, exit codes, risk/identity, and exported APIs are compatibility contracts.\n  When forwarding or echoing accepted input, preserve it verbatim unless its\n  contract defines normalization; never silently substitute another behavior.\n- Success data goes to stdout; typed failure envelopes, progress, warnings, and\n  hints go to stderr. Predicate/self-contained results and partial failures are\n  documented exceptions whose complete result remains on stdout.\n- Keep new or touched Cobra code as wiring. Lark/Feishu API calls in shortcuts go\n  through `*common.RuntimeContext`; direct HTTP is only for non-gateway protocols\n  such as presigned storage and requires a precise `//nolint:forbidigo` reason.\n- Keep user/workspace FileIO invocation-scoped: use `runtime.FileIO()`,\n  `runtime.ValidatePath()`, and `runtime.ResolveSavePath()` so portable commands do\n  not assume a local host or process working directory.\n- Shortcuts do not use `internal/vfs` for user/workspace files. A narrow\n  `//nolint:depguard` waiver is allowed only for CLI-owned state or explicitly\n  CLI-managed host configuration; explain that ownership boundary. Other internal\n  filesystem code uses `internal/vfs` and validates paths.\n- If FileIO lacks a host-local tree operation, prefer an owning `internal/` package\n  or optional capability. Direct `os` calls require a stated local-only boundary,\n  validated and bounded paths, and a precise `//nolint:forbidigo` reason.\n- Do not hardcode resolver-owned hosts. At new API boundaries, or when changed\n  behavior consumes fields from a loose map, project that shape into a typed\n  struct before downstream use. Extend published interfaces through optional\n  interfaces rather than breaking external implementations.\n- Source guards enforce raw HTTP/os/vfs, resolver-host, and migrated-error\n  constructs; other semantics rely on tests and review. Every exemption must be\n  narrow, local, and explain why the safe path does not apply.\n\n## Structured Errors\n\nBefore changing a command failure, taxonomy, or error wire field, read the\n[error contract](errs/ERROR_CONTRACT.md); it owns constructor selection, wrapping,\nextension fields, stability, and CI guards.\n\n- Command-facing failures use typed `errs.*` unless the error contract defines\n  an output-control exception. Never return a final plain `fmt.Errorf` /\n  `errors.New` or ad hoc envelope; pass typed errors through and preserve causes.\n- Lark API failures use a domain typed wrapper, `runtime.CallAPITyped`, or\n  `runtime.DoAPIJSONTyped`; raw callers use `runtime.ClassifyAPIResponse` or\n  `errclass.BuildAPIError`.\n- `param` names only failing user input; recovery belongs in `hint`. Populate\n  `missing_scopes`, `log_id`, and similar fields only from known runtime evidence.\n- Error tests assert typed metadata and cause preservation, not message text alone.\n\n## Affordance and Skills\n\nBefore editing command guidance, read the [affordance guide](affordance/README.md).\nFor plugin distributions, read [Ship skills and command guidance](extension/platform/README.md#ship-skills-and-command-guidance).\n\n- Go metadata/schema owns WHAT; affordance owns command-level WHEN; `SKILL.md`\n  owns domain routing, concepts, safety, and cross-command workflows; `references/`\n  owns detailed or conditional HOW.\n- Do not duplicate canonical descriptions, schemas, or generic error taxonomy.\n  Keep workflow-specific recovery in a skill when it changes agent behavior;\n  affordance examples remain runnable, current, and safe.\n- Skill frontmatter `description` is a concise WHAT/WHEN/NOT routing trigger. Keep\n  always-needed decisions in `SKILL.md`; move conditional detail to `references/`.\n- Skill names and reference paths are public pointers. Every path reachable from\n  shipped docs must ship. Before referencing a new content directory, update\n  `content_embed.go` and add an embedded-FS reachability test; `assets/` and\n  `scripts/` stay source-only unless the distribution contract changes.\n\n## Tests\n\n- Every behavior change needs a nearby test that fails if the implementation is\n  reverted; assert fields, requests, typed errors, or side effects directly.\n- Command/shortcut tests needing a Factory use `cmdutil.TestFactory(t, config)`;\n  isolate config with\n  `t.Setenv(\"LARKSUITE_CLI_CONFIG_DIR\", t.TempDir())`.\n- Tests must not depend on developer profiles, keychains, home directories,\n  execution order, or real credentials unless explicitly live.\n- Live E2E flows are self-contained: create, use, and clean up even after failure.\n\n| Shortcut change | Dry-run E2E | Live E2E |\n|-----------------|:-----------:|:--------:|\n| New shortcut | Required | Required |\n| Flags or request params | Required | Required if behavior changes |\n| Bug fix | Required | Required when risk reaches the API boundary |\n| Internal refactor, no behavior change | Not needed | Not needed |\n\nDry-run tests use placeholder credentials and assert method, URL, params, and\nbody without a real API call. Confirm contracts with `--help` and `schema` first.\nIf no deterministic, cleanable live flow exists, do not leak tenant state or add\na flaky test; document the blocker, fixture conditions, and substitute evidence.\n\n## Validation\n\nRun the narrowest useful check while iterating, then broaden with risk:\n\n| Change | Checks |\n|--------|--------|\n| Go package | `go test ./path/to/package/...`, then the pre-PR Go checks below |\n| Broad/cross-cutting | `make test` |\n| Committed command/help/schema surface | `make quality-gate` |\n| Skills | `node scripts/skill-format-check/index.js`, then `make quality-gate` after committing the change |\n| Affordance | Add/update `internal/affordance/*_source_test.go`; run `go test ./internal/affordance ./cmd/service ./internal/schema` |\n| Make-covered scripts/workflows | `make script-test` |\n| Public plugin SDK | `make examples-build` plus relevant `tests/plugin_e2e` |\n| Auth sidecar | `make sidecar-test` |\n| Skills sync behavior | `make live-skills-test` |\n| Dependencies | `go mod tidy` plus the CI `go-licenses` check |\n\n`make quality-gate` and diff-scoped linters compare the base with `HEAD`; they\nignore staged, unstaged, and untracked changes, so run them after committing.\nSome skill-quality signals are warnings; frontmatter has the separate hard check\nabove. The gate does not validate affordance examples or references in this file:\nrun the focused source test and verify changed paths/symbols directly.\n\n`make test` currently leaves root binaries `audit-observer` and `readonly-policy`; do not stage them.\n\nBefore a Go PR, run `make unit-test`, `make vet`, and `make fmt-check`;\n`go mod tidy` must leave module files unchanged. Set\n`QUALITY_GATE_CHANGED_FROM` to the PR base before diff-scoped checks. Pinned\n`go run module@version` commands need module access unless cached.\n\n```bash\ngo mod tidy\ngit diff --exit-code -- go.mod go.sum\ngo run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.6 run --new-from-rev=\"$QUALITY_GATE_CHANGED_FROM\"\ngo run -C lint . --changed-from \"$QUALITY_GATE_CHANGED_FROM\" ..\ngo test -C lint ./... -count=1\ngo run github.com/google/go-licenses/v2@v2.0.1 check ./... --disallowed_types=forbidden,restricted,reciprocal,unknown\n```\n\nCI is authoritative; state exactly which relevant checks were not run.\n\n## Maintaining This File\n\nAdd a root rule only when it is repository-specific, non-obvious, actionable,\nand prevents a recurring failure or high-impact contract breach. Prefer code,\ntests, or CI for mechanizable constraints; keep only rationale and safe exceptions\nhere. Update named references in the same PR, and delete or move stale, obvious,\nredundant, task-local, or fully enforced rules. Each edit should reduce ambiguity,\nnot only add text.\n\n## Commit and PR\n\nUse English Conventional Commits/PR titles, complete the PR template, and never\ncommit secrets, tokens, internal endpoints, or sensitive test data.\n"},"files":{"AGENTS.md":"# AGENTS.md\n\n## Purpose\n\n`lark-cli` is the official Lark/Feishu CLI for humans and AI agents. Optimize\nfor predictable machine-readable behavior without making the human CLI worse.\n\nKeep each PR focused on one goal: CLI UX, reliability, simpler explicit code,\nor a useful gate. Done means the correct implementation surface, preserved\ncontracts unless a break was requested, and reported checks.\n\nPublic behavior, tests, lint, and CI define current contracts. Existing code is\nevidence, but a legacy exception is not precedent; `Proposal` documents are\ndirection only. Do not mix unrelated cleanup, hand-edit generated files, weaken\ngates, or broaden allowlists to make CI pass.\n\n## Implementation Discipline\n\nUse this sequence for product behavior or enforcement changes:\n\n1. Establish the current contract and owner before choosing a solution. Trace the\n   flow from the command or shortcut through runtime and internal owners to wire\n   output; inspect affected callers and tests, then choose the surface below.\n2. Apply YAGNI to scope. Implement the behavior required now; do not add\n   speculative modes, configuration, compatibility paths, extension points, or\n   scaffolding.\n3. Reuse the project's existing machinery before creating a parallel path.\n   Prefer the owning generic, runtime, or internal surface, then the Go standard\n   library or an existing dependency, while preserving the contracts below.\n4. Fix the root cause at the narrowest cohesive boundary shared by affected\n   callers. Keep command and domain policy at the caller unless there is a real\n   cross-command invariant for an internal owner to enforce.\n5. Ship the smallest complete change: implementation, a revert-failing regression\n   test for behavior or enforcement, and required contract or guidance updates.\n\nOptimize for minimum owned complexity, not minimum diff or line count. A correct\nroot-cause fix may touch the owner, callers, tests, and docs; a one-line workaround\nat the wrong layer is not simpler. Prefer deletion and boring explicit code, and\navoid one-use abstractions or new dependencies for straightforward behavior.\n\nYAGNI never overrides explicit requirements or output, error, path, security,\ncompatibility, and data-safety contracts. If a deliberately limited solution has\na real ceiling, document the ceiling and the concrete condition for expanding it\nat the decision point.\n\n## Build\n\nRun `make build` for the canonical local build; it writes `./lark-cli` with\nversion metadata and the embedded service catalog. It, `make vet`,\n`make unit-test`, `make live-skills-test`, and dependent targets first run\n`python3 scripts/fetch_meta.py`, so Python 3 is required. On a clean checkout,\nthe ignored `internal/registry/meta_data.json` is absent and the first run needs\naccess to `open.feishu.cn`; a valid existing file is reused.\n`LARKSUITE_CLI_REMOTE_META=off` does not disable this build-time fetch.\n`make live-skills-test` requires working `npx` and network access.\n\nIf the fetch fails before Go starts, report the missing Python or network\nprerequisite instead of changing product code or generated metadata. `go build .`\nmay compile against the tracked empty fallback metadata, but that is only a\ndegraded compile check without the full service catalog.\n\n## Choose the Correct Surface\n\n| Need | Implement in | Rule |\n|------|--------------|------|\n| Agent/human-friendly workflow, composition, or smart defaults | `shortcuts/<domain>/` via `common.Shortcut` | Must add UX or workflow value beyond exposing one endpoint. |\n| One-to-one supported OpenAPI method | Upstream service metadata + generic `cmd/service/` machinery | Verify it with `schema` after the canonical metadata fetch. `internal/registry/meta_data.json` is generated and ignored; never hand-edit it or add a shortcut merely to expose a missing catalog method. |\n| Arbitrary OpenAPI endpoint | Generic `cmd/api/` machinery | Keep it endpoint-agnostic. |\n| Auth, config, profile, update, or CLI lifecycle | `cmd/<area>/` plus the owning shared/internal package | Keep new Cobra code as wiring when a lower owner exists. |\n| EventKey, payload shape, or domain projection | `events/<domain>/` | Shared event mechanics stay in `internal/event/`; CLI assembly stays in `cmd/event/`. |\n| Command-independent mechanism or cross-command invariant | Owning `internal/<area>/` package | Keep UX/domain policy at the caller; use a cohesive owner, not a generic utils package. Test the owner and affected caller contracts. |\n| Public plugin or host integration | `extension/` | Exported symbols are compatibility commitments; orchestration stays internal. |\n| Per-command decision guidance: when, avoid, prerequisites, tips, or examples | `affordance/<domain>.md` | Enrich `--help` and `schema` without restating command descriptions, flags, or field schemas. |\n| Domain routing, concepts, safety, or cross-command agent workflow | `skills/<name>/SKILL.md` and `references/` | Keep always-needed decisions in `SKILL.md`, conditional HOW in references, and link commands from affordance. |\n\nDo not duplicate one command surface inside another. Register new shortcuts in\nthe domain's `Shortcuts()`; declare risk, identities/scopes, flags, and dry-run.\n\n## Hard Contracts\n\nRead the [JSON output contract](README.md#json-output-contract) before changing\nwire output. Read the [source guard guide](lint/README.md) and `.golangci.yml`\nbefore changing or waiving enforcement.\n\n- Command/flag semantics, help/schema metadata, output placement and shapes,\n  errors, exit codes, risk/identity, and exported APIs are compatibility contracts.\n  When forwarding or echoing accepted input, preserve it verbatim unless its\n  contract defines normalization; never silently substitute another behavior.\n- Success data goes to stdout; typed failure envelopes, progress, warnings, and\n  hints go to stderr. Predicate/self-contained results and partial failures are\n  documented exceptions whose complete result remains on stdout.\n- Keep new or touched Cobra code as wiring. Lark/Feishu API calls in shortcuts go\n  through `*common.RuntimeContext`; direct HTTP is only for non-gateway protocols\n  such as presigned storage and requires a precise `//nolint:forbidigo` reason.\n- Keep user/workspace FileIO invocation-scoped: use `runtime.FileIO()`,\n  `runtime.ValidatePath()`, and `runtime.ResolveSavePath()` so portable commands do\n  not assume a local host or process working directory.\n- Shortcuts do not use `internal/vfs` for user/workspace files. A narrow\n  `//nolint:depguard` waiver is allowed only for CLI-owned state or explicitly\n  CLI-managed host configuration; explain that ownership boundary. Other internal\n  filesystem code uses `internal/vfs` and validates paths.\n- If FileIO lacks a host-local tree operation, prefer an owning `internal/` package\n  or optional capability. Direct `os` calls require a stated local-only boundary,\n  validated and bounded paths, and a precise `//nolint:forbidigo` reason.\n- Do not hardcode resolver-owned hosts. At new API boundaries, or when changed\n  behavior consumes fields from a loose map, project that shape into a typed\n  struct before downstream use. Extend published interfaces through optional\n  interfaces rather than breaking external implementations.\n- Source guards enforce raw HTTP/os/vfs, resolver-host, and migrated-error\n  constructs; other semantics rely on tests and review. Every exemption must be\n  narrow, local, and explain why the safe path does not apply.\n\n## Structured Errors\n\nBefore changing a command failure, taxonomy, or error wire field, read the\n[error contract](errs/ERROR_CONTRACT.md); it owns constructor selection, wrapping,\nextension fields, stability, and CI guards.\n\n- Command-facing failures use typed `errs.*` unless the error contract defines\n  an output-control exception. Never return a final plain `fmt.Errorf` /\n  `errors.New` or ad hoc envelope; pass typed errors through and preserve causes.\n- Lark API failures use a domain typed wrapper, `runtime.CallAPITyped`, or\n  `runtime.DoAPIJSONTyped`; raw callers use `runtime.ClassifyAPIResponse` or\n  `errclass.BuildAPIError`.\n- `param` names only failing user input; recovery belongs in `hint`. Populate\n  `missing_scopes`, `log_id`, and similar fields only from known runtime evidence.\n- Error tests assert typed metadata and cause preservation, not message text alone.\n\n## Affordance and Skills\n\nBefore editing command guidance, read the [affordance guide](affordance/README.md).\nFor plugin distributions, read [Ship skills and command guidance](extension/platform/README.md#ship-skills-and-command-guidance).\n\n- Go metadata/schema owns WHAT; affordance owns command-level WHEN; `SKILL.md`\n  owns domain routing, concepts, safety, and cross-command workflows; `references/`\n  owns detailed or conditional HOW.\n- Do not duplicate canonical descriptions, schemas, or generic error taxonomy.\n  Keep workflow-specific recovery in a skill when it changes agent behavior;\n  affordance examples remain runnable, current, and safe.\n- Skill frontmatter `description` is a concise WHAT/WHEN/NOT routing trigger. Keep\n  always-needed decisions in `SKILL.md`; move conditional detail to `references/`.\n- Skill names and reference paths are public pointers. Every path reachable from\n  shipped docs must ship. Before referencing a new content directory, update\n  `content_embed.go` and add an embedded-FS reachability test; `assets/` and\n  `scripts/` stay source-only unless the distribution contract changes.\n\n## Tests\n\n- Every behavior change needs a nearby test that fails if the implementation is\n  reverted; assert fields, requests, typed errors, or side effects directly.\n- Command/shortcut tests needing a Factory use `cmdutil.TestFactory(t, config)`;\n  isolate config with\n  `t.Setenv(\"LARKSUITE_CLI_CONFIG_DIR\", t.TempDir())`.\n- Tests must not depend on developer profiles, keychains, home directories,\n  execution order, or real credentials unless explicitly live.\n- Live E2E flows are self-contained: create, use, and clean up even after failure.\n\n| Shortcut change | Dry-run E2E | Live E2E |\n|-----------------|:-----------:|:--------:|\n| New shortcut | Required | Required |\n| Flags or request params | Required | Required if behavior changes |\n| Bug fix | Required | Required when risk reaches the API boundary |\n| Internal refactor, no behavior change | Not needed | Not needed |\n\nDry-run tests use placeholder credentials and assert method, URL, params, and\nbody without a real API call. Confirm contracts with `--help` and `schema` first.\nIf no deterministic, cleanable live flow exists, do not leak tenant state or add\na flaky test; document the blocker, fixture conditions, and substitute evidence.\n\n## Validation\n\nRun the narrowest useful check while iterating, then broaden with risk:\n\n| Change | Checks |\n|--------|--------|\n| Go package | `go test ./path/to/package/...`, then the pre-PR Go checks below |\n| Broad/cross-cutting | `make test` |\n| Committed command/help/schema surface | `make quality-gate` |\n| Skills | `node scripts/skill-format-check/index.js`, then `make quality-gate` after committing the change |\n| Affordance | Add/update `internal/affordance/*_source_test.go`; run `go test ./internal/affordance ./cmd/service ./internal/schema` |\n| Make-covered scripts/workflows | `make script-test` |\n| Public plugin SDK | `make examples-build` plus relevant `tests/plugin_e2e` |\n| Auth sidecar | `make sidecar-test` |\n| Skills sync behavior | `make live-skills-test` |\n| Dependencies | `go mod tidy` plus the CI `go-licenses` check |\n\n`make quality-gate` and diff-scoped linters compare the base with `HEAD`; they\nignore staged, unstaged, and untracked changes, so run them after committing.\nSome skill-quality signals are warnings; frontmatter has the separate hard check\nabove. The gate does not validate affordance examples or references in this file:\nrun the focused source test and verify changed paths/symbols directly.\n\n`make test` currently leaves root binaries `audit-observer` and `readonly-policy`; do not stage them.\n\nBefore a Go PR, run `make unit-test`, `make vet`, and `make fmt-check`;\n`go mod tidy` must leave module files unchanged. Set\n`QUALITY_GATE_CHANGED_FROM` to the PR base before diff-scoped checks. Pinned\n`go run module@version` commands need module access unless cached.\n\n```bash\ngo mod tidy\ngit diff --exit-code -- go.mod go.sum\ngo run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.6 run --new-from-rev=\"$QUALITY_GATE_CHANGED_FROM\"\ngo run -C lint . --changed-from \"$QUALITY_GATE_CHANGED_FROM\" ..\ngo test -C lint ./... -count=1\ngo run github.com/google/go-licenses/v2@v2.0.1 check ./... --disallowed_types=forbidden,restricted,reciprocal,unknown\n```\n\nCI is authoritative; state exactly which relevant checks were not run.\n\n## Maintaining This File\n\nAdd a root rule only when it is repository-specific, non-obvious, actionable,\nand prevents a recurring failure or high-impact contract breach. Prefer code,\ntests, or CI for mechanizable constraints; keep only rationale and safe exceptions\nhere. Update named references in the same PR, and delete or move stale, obvious,\nredundant, task-local, or fully enforced rules. Each edit should reduce ambiguity,\nnot only add text.\n\n## Commit and PR\n\nUse English Conventional Commits/PR titles, complete the PR template, and never\ncommit secrets, tokens, internal endpoints, or sensitive test data.\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","title":"AGENTS.md","content":"# AGENTS.md\n\n## Purpose\n\n`lark-cli` is the official Lark/Feishu CLI for humans and AI agents. Optimize\nfor predictable machine-readable behavior without making the human CLI worse.\n\nKeep each PR focused on one goal: CLI UX, reliability, simpler explicit code,\nor a useful gate. Done means the correct implementation surface, preserved\ncontracts unless a break was requested, and reported checks.\n\nPublic behavior, tests, lint, and CI define current contracts. Existing code is\nevidence, but a legacy exception is not precedent; `Proposal` documents are\ndirection only. Do not mix unrelated cleanup, hand-edit generated files, weaken\ngates, or broaden allowlists to make CI pass.\n\n## Implementation Discipline\n\nUse this sequence for product behavior or enforcement changes:\n\n1. Establish the current contract and owner before choosing a solution. Trace the\n   flow from the command or shortcut through runtime and internal owners to wire\n   output; inspect affected callers and tests, then choose the surface below.\n2. Apply YAGNI to scope. Implement the behavior required now; do not add\n   speculative modes, configuration, compatibility paths, extension points, or\n   scaffolding.\n3. Reuse the project's existing machinery before creating a parallel path.\n   Prefer the owning generic, runtime, or internal surface, then the Go standard\n   library or an existing dependency, while preserving the contracts below.\n4. Fix the root cause at the narrowest cohesive boundary shared by affected\n   callers. Keep command and domain policy at the caller unless there is a real\n   cross-command invariant for an internal owner to enforce.\n5. Ship the smallest complete change: implementation, a revert-failing regression\n   test for behavior or enforcement, and required contract or guidance updates.\n\nOptimize for minimum owned complexity, not minimum diff or line count. A correct\nroot-cause fix may touch the owner, callers, tests, and docs; a one-line workaround\nat the wrong layer is not simpler. Prefer deletion and boring explicit code, and\navoid one-use abstractions or new dependencies for straightforward behavior.\n\nYAGNI never overrides explicit requirements or output, error, path, security,\ncompatibility, and data-safety contracts. If a deliberately limited solution has\na real ceiling, document the ceiling and the concrete condition for expanding it\nat the decision point.\n\n## Build\n\nRun `make build` for the canonical local build; it writes `./lark-cli` with\nversion metadata and the embedded service catalog. It, `make vet`,\n`make unit-test`, `make live-skills-test`, and dependent targets first run\n`python3 scripts/fetch_meta.py`, so Python 3 is required. On a clean checkout,\nthe ignored `internal/registry/meta_data.json` is absent and the first run needs\naccess to `open.feishu.cn`; a valid existing file is reused.\n`LARKSUITE_CLI_REMOTE_META=off` does not disable this build-time fetch.\n`make live-skills-test` requires working `npx` and network access.\n\nIf the fetch fails before Go starts, report the missing Python or network\nprerequisite instead of changing product code or generated metadata. `go build .`\nmay compile against the tracked empty fallback metadata, but that is only a\ndegraded compile check without the full service catalog.\n\n## Choose the Correct Surface\n\n| Need | Implement in | Rule |\n|------|--------------|------|\n| Agent/human-friendly workflow, composition, or smart defaults | `shortcuts/<domain>/` via `common.Shortcut` | Must add UX or workflow value beyond exposing one endpoint. |\n| One-to-one supported OpenAPI method | Upstream service metadata + generic `cmd/service/` machinery | Verify it with `schema` after the canonical metadata fetch. `internal/registry/meta_data.json` is generated and ignored; never hand-edit it or add a shortcut merely to expose a missing catalog method. |\n| Arbitrary OpenAPI endpoint | Generic `cmd/api/` machinery | Keep it endpoint-agnostic. |\n| Auth, config, profile, update, or CLI lifecycle | `cmd/<area>/` plus the owning shared/internal package | Keep new Cobra code as wiring when a lower owner exists. |\n| EventKey, payload shape, or domain projection | `events/<domain>/` | Shared event mechanics stay in `internal/event/`; CLI assembly stays in `cmd/event/`. |\n| Command-independent mechanism or cross-command invariant | Owning `internal/<area>/` package | Keep UX/domain policy at the caller; use a cohesive owner, not a generic utils package. Test the owner and affected caller contracts. |\n| Public plugin or host integration | `extension/` | Exported symbols are compatibility commitments; orchestration stays internal. |\n| Per-command decision guidance: when, avoid, prerequisites, tips, or examples | `affordance/<domain>.md` | Enrich `--help` and `schema` without restating command descriptions, flags, or field schemas. |\n| Domain routing, concepts, safety, or cross-command agent workflow | `skills/<name>/SKILL.md` and `references/` | Keep always-needed decisions in `SKILL.md`, conditional HOW in references, and link commands from affordance. |\n\nDo not duplicate one command surface inside another. Register new shortcuts in\nthe domain's `Shortcuts()`; declare risk, identities/scopes, flags, and dry-run.\n\n## Hard Contracts\n\nRead the [JSON output contract](README.md#json-output-contract) before changing\nwire output. Read the [source guard guide](lint/README.md) and `.golangci.yml`\nbefore changing or waiving enforcement.\n\n- Command/flag semantics, help/schema metadata, output placement and shapes,\n  errors, exit codes, risk/identity, and exported APIs are compatibility contracts.\n  When forwarding or echoing accepted input, preserve it verbatim unless its\n  contract defines normalization; never silently substitute another behavior.\n- Success data goes to stdout; typed failure envelopes, progress, warnings, and\n  hints go to stderr. Predicate/self-contained results and partial failures are\n  documented exceptions whose complete result remains on stdout.\n- Keep new or touched Cobra code as wiring. Lark/Feishu API calls in shortcuts go\n  through `*common.RuntimeContext`; direct HTTP is only for non-gateway protocols\n  such as presigned storage and requires a precise `//nolint:forbidigo` reason.\n- Keep user/workspace FileIO invocation-scoped: use `runtime.FileIO()`,\n  `runtime.ValidatePath()`, and `runtime.ResolveSavePath()` so portable commands do\n  not assume a local host or process working directory.\n- Shortcuts do not use `internal/vfs` for user/workspace files. A narrow\n  `//nolint:depguard` waiver is allowed only for CLI-owned state or explicitly\n  CLI-managed host configuration; explain that ownership boundary. Other internal\n  filesystem code uses `internal/vfs` and validates paths.\n- If FileIO lacks a host-local tree operation, prefer an owning `internal/` package\n  or optional capability. Direct `os` calls require a stated local-only boundary,\n  validated and bounded paths, and a precise `//nolint:forbidigo` reason.\n- Do not hardcode resolver-owned hosts. At new API boundaries, or when changed\n  behavior consumes fields from a loose map, project that shape into a typed\n  struct before downstream use. Extend published interfaces through optional\n  interfaces rather than breaking external implementations.\n- Source guards enforce raw HTTP/os/vfs, resolver-host, and migrated-error\n  constructs; other semantics rely on tests and review. Every exemption must be\n  narrow, local, and explain why the safe path does not apply.\n\n## Structured Errors\n\nBefore changing a command failure, taxonomy, or error wire field, read the\n[error contract](errs/ERROR_CONTRACT.md); it owns constructor selection, wrapping,\nextension fields, stability, and CI guards.\n\n- Command-facing failures use typed `errs.*` unless the error contract defines\n  an output-control exception. Never return a final plain `fmt.Errorf` /\n  `errors.New` or ad hoc envelope; pass typed errors through and preserve causes.\n- Lark API failures use a domain typed wrapper, `runtime.CallAPITyped`, or\n  `runtime.DoAPIJSONTyped`; raw callers use `runtime.ClassifyAPIResponse` or\n  `errclass.BuildAPIError`.\n- `param` names only failing user input; recovery belongs in `hint`. Populate\n  `missing_scopes`, `log_id`, and similar fields only from known runtime evidence.\n- Error tests assert typed metadata and cause preservation, not message text alone.\n\n## Affordance and Skills\n\nBefore editing command guidance, read the [affordance guide](affordance/README.md).\nFor plugin distributions, read [Ship skills and command guidance](extension/platform/README.md#ship-skills-and-command-guidance).\n\n- Go metadata/schema owns WHAT; affordance owns command-level WHEN; `SKILL.md`\n  owns domain routing, concepts, safety, and cross-command workflows; `references/`\n  owns detailed or conditional HOW.\n- Do not duplicate canonical descriptions, schemas, or generic error taxonomy.\n  Keep workflow-specific recovery in a skill when it changes agent behavior;\n  affordance examples remain runnable, current, and safe.\n- Skill frontmatter `description` is a concise WHAT/WHEN/NOT routing trigger. Keep\n  always-needed decisions in `SKILL.md`; move conditional detail to `references/`.\n- Skill names and reference paths are public pointers. Every path reachable from\n  shipped docs must ship. Before referencing a new content directory, update\n  `content_embed.go` and add an embedded-FS reachability test; `assets/` and\n  `scripts/` stay source-only unless the distribution contract changes.\n\n## Tests\n\n- Every behavior change needs a nearby test that fails if the implementation is\n  reverted; assert fields, requests, typed errors, or side effects directly.\n- Command/shortcut tests needing a Factory use `cmdutil.TestFactory(t, config)`;\n  isolate config with\n  `t.Setenv(\"LARKSUITE_CLI_CONFIG_DIR\", t.TempDir())`.\n- Tests must not depend on developer profiles, keychains, home directories,\n  execution order, or real credentials unless explicitly live.\n- Live E2E flows are self-contained: create, use, and clean up even after failure.\n\n| Shortcut change | Dry-run E2E | Live E2E |\n|-----------------|:-----------:|:--------:|\n| New shortcut | Required | Required |\n| Flags or request params | Required | Required if behavior changes |\n| Bug fix | Required | Required when risk reaches the API boundary |\n| Internal refactor, no behavior change | Not needed | Not needed |\n\nDry-run tests use placeholder credentials and assert method, URL, params, and\nbody without a real API call. Confirm contracts with `--help` and `schema` first.\nIf no deterministic, cleanable live flow exists, do not leak tenant state or add\na flaky test; document the blocker, fixture conditions, and substitute evidence.\n\n## Validation\n\nRun the narrowest useful check while iterating, then broaden with risk:\n\n| Change | Checks |\n|--------|--------|\n| Go package | `go test ./path/to/package/...`, then the pre-PR Go checks below |\n| Broad/cross-cutting | `make test` |\n| Committed command/help/schema surface | `make quality-gate` |\n| Skills | `node scripts/skill-format-check/index.js`, then `make quality-gate` after committing the change |\n| Affordance | Add/update `internal/affordance/*_source_test.go`; run `go test ./internal/affordance ./cmd/service ./internal/schema` |\n| Make-covered scripts/workflows | `make script-test` |\n| Public plugin SDK | `make examples-build` plus relevant `tests/plugin_e2e` |\n| Auth sidecar | `make sidecar-test` |\n| Skills sync behavior | `make live-skills-test` |\n| Dependencies | `go mod tidy` plus the CI `go-licenses` check |\n\n`make quality-gate` and diff-scoped linters compare the base with `HEAD`; they\nignore staged, unstaged, and untracked changes, so run them after committing.\nSome skill-quality signals are warnings; frontmatter has the separate hard check\nabove. The gate does not validate affordance examples or references in this file:\nrun the focused source test and verify changed paths/symbols directly.\n\n`make test` currently leaves root binaries `audit-observer` and `readonly-policy`; do not stage them.\n\nBefore a Go PR, run `make unit-test`, `make vet`, and `make fmt-check`;\n`go mod tidy` must leave module files unchanged. Set\n`QUALITY_GATE_CHANGED_FROM` to the PR base before diff-scoped checks. Pinned\n`go run module@version` commands need module access unless cached.\n\n```bash\ngo mod tidy\ngit diff --exit-code -- go.mod go.sum\ngo run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.6 run --new-from-rev=\"$QUALITY_GATE_CHANGED_FROM\"\ngo run -C lint . --changed-from \"$QUALITY_GATE_CHANGED_FROM\" ..\ngo test -C lint ./... -count=1\ngo run github.com/google/go-licenses/v2@v2.0.1 check ./... --disallowed_types=forbidden,restricted,reciprocal,unknown\n```\n\nCI is authoritative; state exactly which relevant checks were not run.\n\n## Maintaining This File\n\nAdd a root rule only when it is repository-specific, non-obvious, actionable,\nand prevents a recurring failure or high-impact contract breach. Prefer code,\ntests, or CI for mechanizable constraints; keep only rationale and safe exceptions\nhere. Update named references in the same PR, and delete or move stale, obvious,\nredundant, task-local, or fully enforced rules. Each edit should reduce ambiguity,\nnot only add text.\n\n## Commit and PR\n\nUse English Conventional Commits/PR titles, complete the PR template, and never\ncommit secrets, tokens, internal endpoints, or sensitive test data.\n","category":"root","tokens":3347}]}