Miaoda apps are user assets. By default use --as user; authentication, scope, exit-10, high-risk confirmation,_notice and other general handling read only ../lark-shared/SKILL.md, do not copy them in this skill. Miaoda apps have two development paths:Local development(pull source code and write locally) / Cloud session(Miaoda AI generation).
Identity and Authorization
A Miaoda app is a user's personal asset, uniformly --as user(see the beginning). When an existing user identity is available, directly execute business commands,do not proactively log in again to prevent permission issues, otherwise it may interrupt the original task and trigger unnecessary device authorization. Only when the CLI explicitly returns not logged in or missing the scope for this domain, execute once:
lark-cli auth login --domain apps
For general handling when it fails due to missing permissions (error.subtype == "missing_scope"), see ../lark-shared/SKILL.md, also authorize according to --domain apps ; after successful authorization, only resume the original business operation, do not expand the task scope.
Intent Routing
Look up commands by specific operation (for the development path, first use the "Select Development Path" decision table below to determine it, then come back to get commands):
| User intent | First use | Read on demand |
|---|---|---|
| Createnewapp asset, get app_id | +create |
lark-apps-create.md |
| Find an existing app_id, filter apps by name | +list --keyword <name> |
lark-apps-list.md |
| View details of a single app (type, name, publish status, etc.) | +get --app-id <app_id> |
lark-apps-get.md |
| Change app name or description | +update |
lark-apps-update.md |
| HTML app / creative mode — write HTML pages/websites, static pages, PPT/deck, landing pages, dashboards, UI mockups, prototypes, wireframes, visual exploration | Load creative-design/creative-design.md(includes the complete development and publishing process) |
creative-design/creative-design.md |
| Legacy existing HTML apps (without Git management) continue to upload existing static artifacts | +html-publish(only compatible with the legacy pipeline; must not be used for newly created html / creative mode / creative-design artifacts) |
lark-apps-html-publish.md |
Develop an existing app / initialize a local repository (after the development method has been determined to be local; first resolve app_id, do not +create create new) |
+init(or manually +git-credential-init + native git).Required reading before execution lark-apps-local-dev.md, includes the end-to-end process and domain rules |
lark-apps-init.md, lark-apps-git-credential.md |
| Only want a source code snapshot, without doing local development; or want to getshared with you by someone elseapp source code (you have no permission on its repository) | +export(download zip; do not configure git credentials, do not create a workspace). To continue development use +init instead of this command |
lark-apps-export.md |
During local development .env.local is damaged/lost, re-pull the startup environment variables |
+env-pull |
lark-apps-env-pull.md |
| Manage app environment variables (view/set/delete) | +env-list, +env-set, +env-delete |
lark-apps-env.md |
| View online logs, Trace, request count, error rate, latency, CPU, memory, PV/UV/visit count | +log-list, +log-get, +trace-list, +trace-get, +metric-list, +analytics-list |
lark-apps-observability.md |
| View tables / view structure / initialize multiple environments / import and export data / change tracking / row-level audit / dev→online release / point-in-time recovery / check DB usage | +db-table-list、+db-table-get、+db-env-create、+db-data-export/+db-data-import、+db-changelog-list、+db-audit-status/+db-audit-enable/+db-audit-disable/+db-audit-list、+db-env-diff/+db-env-migrate、+db-recovery-diff/+db-recovery-apply、+db-quota-get |
lark-apps-db.md |
| Execute SQL statement by statement (SELECT / DML / DDL); platform conventions for creating tables / altering tables / writing SQL | +db-execute |
lark-apps-db-execute.md(including "Platform SQL Conventions": audit columns / RLS / user_profile / prohibited SQL / PG pitfalls) |
| Manage application file storage: upload/download local files, list/view/delete stored files, generate temporary share links, check storage usage | +file-upload/+file-download/+file-list/+file-get/+file-sign/+file-delete/+file-quota-get |
lark-apps-file.md |
| Debug application runtime cache: view/delete a single business key, clear the cache for a specified environment | +cache-get/+cache-delete/+cache-clear |
lark-apps-cache.md |
| Deploy/release the application("deploy" "release" "push it up and deploy" "publish to the cloud"); check release status/history | For the local development workflow, first use lark-apps-local-dev.md to confirm this change has been git committed + git pushed, then use +release-create / +release-get; to check history use +release-list |
lark-apps-local-dev.md, lark-apps-release-create.md, lark-apps-release-get.md, lark-apps-release-list.md |
| Set or view the runtime visibility scope | +access-scope-set, +access-scope-get |
Corresponding access-scope reference |
| Manage application collaborators (list/add/change permissions/remove) or collaboration permission settings | +member-list, +member-add, +member-update, +member-remove, +member-settings-get, +member-settings-set |
The "Application Collaborators and Collaboration Permission Settings" section in this document |
| Comment-related operations for creative mode (html) applications | Creative mode application comments use the lark-drive document comment system; read ../lark-drive/SKILL.md to learn about comment capabilities |
../lark-drive/SKILL.md |
Manage app_... in-app roles and role members, or query the roles a user matches |
+role-list/get/create/update/delete, +role-member-list/add/remove, +role-match-list |
lark-apps-role.md |
| Cloud Agent generates/iterates applications (after the development method has been decided as cloud) | +session-create -> +chat -> +session-get |
lark-apps-cloud-dev.md |
| Manage Miaoda application open API Keys (create/view/enable-disable/reset/delete credentials; the secret is returned only once on create/reset) | +openapi-key-list/get/create/update/enable/disable/delete/reset |
lark-apps-openapi-key.md |
| Manage Miaoda application automation triggers (query/create/update/enable-disable for the four trigger types: scheduled/record change/Webhook/Feishu approval; Webhook URL·Token is echoed back only once and is not persisted) | +automation-list/get/create/update/enable/disable |
lark-apps-automation.md |
| View the reply message of a certain turn in a session (including the current turn still being generated) / export the previous turn's model reply ("what was replied in this turn" "the previous turn's reply" "export a certain turn's messages") | First +session-get(get latest_turn.turn_id)-> +session-messages-list --turn-id <id>(only the user identity; for pagination use --page-token) |
lark-apps-session-messages-list.md |
| External capabilities (AI model capabilities and Feishu platform capabilities) integration/plugin/Plugin/Capability | +plugin-install, +plugin-list, +plugin-uninstall |
lark-apps-plugin-install.md, lark-apps-plugin-uninstall.md, lark-apps-plugin-list.md |
| Convert a batch of IDs between Miaoda user_id ↔ Feishu open_id / union_id / Feishu user_id (for example, you have an open_id but the downstream requires a user_id) | +user-id-convert --convert-type <方向> --ids <id1,id2,...> |
lark-apps-user-id-convert.md |
High-frequency paths
- Base to application database sync: when the user says "Base sync to database / full-database sync / multiple-table sync / batch task re-enable / operation-not-allowed", first read the Base data sync section of
lark-apps-db.md, then check the app_id or handle authorization. Form a plan before acting:+db-sync-createhandle only one Base table at a time; full-database/multi-table must be split into multiple single-table configurations and multiple preview/create calls; batch/import tasks are one-time tasks and cannot be re-enabled; when encountering operation-not-allowed, first explain the lifecycle boundary, then use+db-sync-getto check status/results; for continuous sync, create a new streaming task. - Performance/monitoring/observability metrics: When the user asks about "API request volume, error volume, error rate, slow APIs, latency, CPU, memory, last one hour/seven day trends", do not search the current workspace for monitoring files, and do not ask "where is the monitoring data". First resolve the application by "get app_id":
lark-cli apps +list --keyword "<应用名>" --as user; after obtainingapp_id, readlark-apps-observability.md, use+metric-list。 - request volume + error volume + latency: for request volume/error volume use
lark-cli apps +metric-list --app-id <app_id> --metric requests --since <range> --as user(not passing--serieswill return both total/error); for latency use--metric latency(not passing--serieswill return p50/p99). If the user gives a specific API, also add--api <path-or-name>; do not invent group-by parameters. - PV/UV/visit volume/active users: first resolve
app_id, then use+analytics-list, do not mistakenly use+metric-list。 - set environment variables: if the user only gives the application name, still first
+list --keywordresolve app_id; when setting the online environment and the user has already explicitly said "confirm/directly execute", call+env-set --environment online ... --yes, do not ask for confirmation again. In replies and log summaries, only mention key / env / app, do not echo the real value; when complex values need to be passed, prefer@fileor stdin. - delete environment variable:
+env-deleteis a destructive operation. Unless the user has already clearly confirmed in the same turn to delete this app/env/key, first confirm with the user the application, environment, key, and consequences of deletion; after confirmation, then add--yes. Do not automatically continue deletion just because authentication failed/re-login completed; the confirmation threshold must be retained.
Application collaborators and collaboration permission settings
This group of commands manages the development collaborators and collaboration policies of Miaoda applications, and is not equivalent to the runtime access scope of +access-scope-* , nor equivalent to the in-application business roles of +role-* . All commands use app_... application ID and --as user. Do not read or judge app_type to predict the supported scope; directly call the corresponding collaborator command.
+member-list、+member-settings-getis a read-only command, requiresspark:app:read。+member-add、+member-update、+member-remove、+member-settings-setis a high-risk write command, requiresspark:app:write. First use--dry-runto verify the target, URL, and request body; dry-run does not require--yes. When the user has confirmed the specific application, member/settings, and impact, or has explicitly pre-authorized the entire flow according to the "High-impact actions: confirmation and pre-authorization" section below, add--yesfor real execution; otherwise stop after dry-run and request confirmation. Batch removal of members still follows the "bottom line for prohibiting pre-authorization determination", and--yes。- cannot be derived from a generalized "just do it". When adding, updating, or removing members, a matching external ID type must be explicitly provided; passing internal numeric IDs, guessing types, or performing implicit conversion is prohibited: user
--member-type openid --member-id ou_...; group--member-type openchat --member-id oc_...; department--member-type opendepartmentid --member-id od-...。 +member-list --member-typefilter enum is the response object typeuser/department/chat, which is different from the ID type enum of write commands. Can also use--role view|edit|full_accessto filter.+member-listreturns all direct collaborators of the application at once, and does not provide pagination parameters; can use--member-typeand--roleto narrow the result scope.- The member response does not include application details. When the name, type, or publish status is needed, call
+get --app-id <app_id>separately, do not expect member pagination to repeatedly returnapp。 - If subtype
feature_not_available(OpenAPI code3340005is received; direct connection service may be40005), immediately stop CLI automation, do not switchapp_type, and do not attempt to bypass using access scope, app roles, or other member commands. Explain to the user that this app does not currently support setting collaborators via lark-cli, and guide them to operate in the permission settings of the Miaoda backend. external_inviteOnly in+member-settings-get's response is it read; it cannot be set independently; it will followexternal_access. The CLI does not register--external-invite. When external collaboration capability needs to be changed, only set--external-access。copy_download_byis also only read in+member-settings-get's response. CCM currently explicitly does not support writing copy, print, and download permissions for Miaoda objects, so the CLI does not register--copy-download-by. Keep the read result; do not attempt to write, and do not use other permission fields to simulate it.
# 读取协作者和当前协作策略
lark-cli apps +member-list --app-id <app_id> --as user
lark-cli apps +member-settings-get --app-id <app_id> --as user
# 写操作先预览精确的 typed-ID 字段;确认后把 --dry-run 换成 --yes
lark-cli apps +member-add --app-id <app_id> --member-type openid --member-id ou_xxx --perm view --dry-run --as user
lark-cli apps +member-update --app-id <app_id> --member-type openchat --member-id oc_xxx --perm edit --dry-run --as user
lark-cli apps +member-remove --app-id <app_id> --member-type opendepartmentid --member-id od-xxx --dry-run --as user
lark-cli apps +member-settings-set --app-id <app_id> --external-access disabled --comment-by viewer --dry-run --as user
Choose the development path (judge this step before entering intent routing)
Creation must first determine app_type anddevelopment modetwo orthogonal things; for modifying an existing one, first identify the app according to "app_id acquisition"; if it cannot be identified, ask the user, and do not arbitrarily +create. Development mode (local vs cloud) depends only on the user's preference for "who writes the code" and is unrelated to app complexity or whether a database is needed.
Three boundaries of app_type(first judge "whether data needs to be stored on the server", then judge "purely display or interactive"):
| Signal | Judgment |
|---|---|
| Includes database / backend persistence: login / CRUD / registration, voting, standup record storage / multi-person collaboration / generic terms like "system" or "tool" with an explicit need to store data | app_type=full_stack |
| Purely static display (materials for people to "view", no JS interaction): PPT/deck / demo / landing page / poster / UI mockup / wireframe / static dashboard / visual exploration | app_type=html, load creative-design/creative-design.md(including the complete development and release process) |
| Has JS interaction but no database (a frontend app for people to "use"): interactive prototype / SPA / form validation / dynamic calculation / calling external APIs / generic terms like "tool" or "system" but without an explicit need to store data | app_type=frontend(Default tendency: when the user has not explicitly raised a database requirement, default to guiding frontend, not defaulting to full_stack) |
| Ambiguous type (especially unclear "whether to store data") | Ask follow-up, with wording leaning toward frontend, e.g.: "It looks like a frontend app. Does it need to save data?"; after confirming data storage, switch to full_stack; after confirming pure display, switch to html |
| The user wants to write it themselves / local IDE, code agent / pull source code locally / hand over to R&D | Local development, read lark-apps-local-dev.md |
| Have Miaoda AI generate in the cloud / conversational / the user does not touch code themselves | Cloud session, read lark-apps-cloud-dev.md |
| Has not expressed a preference for "who writes" | Must ask first(local code development vs cloud AI generation); before choosing, do not arbitrarily pick a side, do not imply a default, and do not skip the question on the grounds that "the requirement is not ambiguous" and directly +init / git clone / +session-create / first-round +chat |
Modify existing + current directory is a .spark/meta.json project |
Directly continue locally according to intent routing; no need to ask and no need to judge cloud |
| Modify existing + has cloud preference | Cloud session; if no preference is expressed and it is not a local project → default to local; if uncertain, ask first |
Type upgrade:frontend When the app later needs database/backend capabilities, the local CLI does not provide type upgrade; guide the user to a cloud session (open https://miaoda.feishu.cn/app/{app_id}), describe the backend requirement in natural language (e.g. "add login and data storage to this app") to trigger the upgrade, no special instruction needed.
Published-state guardrails
- Publish intent determination: the user wants "accessible / online / share / new link / go live" = publish intent; follow the publish flow first, confirm completion, then give the link.
+release-createpublish reason is handled by app type: creative modehtmldoes not need a publish reason, the command must not pass--apply-reason;frontend/full_stackfirst loadlark-apps-release-create.md, generate the reason and include it in the existing publish confirmation, and the command passes in the same confirmed reason.+release-gethas not yet returnedfinished/failed, and returnscurrent_node_info.current_status=PENDING(the top level may bepublishingorpending) immediately loadlark-apps-release-get.md, stop polling and tell the current user that the approval owner is handling it; do not assume the current user orsubmitted_byis the approver. The terminal state takes precedence over any possibly lingering PENDING node.+release-createor+release-getonly when the server error explicitly states the client version is too old or requires an upgrade, suggest runninglark-cli updateand then retry the original command (queries still use the samerelease_id). Do not hardcode or guess the minimum version, do not use--helpfor capability pre-checks;X-Cli-Versionis uniformly carried by CLI requests and is not authentication information; this workflow does not add a CLI version gate.- Completion ≠ publish: cloud session completion /
+list is_published=trueneither means the latest content has been deployed. - Development-state link
https://miaoda.feishu.cn/app/{app_id}(full_stack / frontend apps): the entry for entering the app edit/development state, managing and continuing to develop the app, and also the entry for upgrading frontend to full_stack (cloud session). For creative mode (html) apps the development state and published state are the same link, no additional development-state link needs to be provided. - Published-state link sources:
+release-getpollfinishedgiveonline_url/failedgiveerror_logs(html / frontend / full_stack uniformly go through+release-get)。 - The main flow of html apps is the creative mode development method: initialize the repository according to
lark-apps-local-dev.md, produce HTML and related files inside the repository, and publish and deploy via git commit / git push /+release-create/+release-get. When any git operation (clone / pull / push) errors, first runlark-cli apps +git-credential-init --app-id <app_id> --as userto refresh local Git credentials, then retry the original git command. If refreshing credentials also fails,stop and report to the user: the original git error, the reason credential refresh failed, and whether it may be caused by the current environment (operating system, sandbox) restrictions (e.g. macOS Keychain unavailable in the sandbox, Linux encrypted file directory not writable, etc.). Do not switch to+html-publish, and do not treat+html-publishas a fallback for the local development flow. - The link format of creative mode (html) apps is
https://{租户域名}/page/{meta_token},the development state and published state are the same link(unlike full_stack apps where the two are separate). This link resembles a Feishu document link.+get --app-id <meta_token>can get app information (includingapp_id),+get --app-id <app_id>can getmeta_token. When you see a/page/xxxlink, it is a Miaoda creative mode app, do not skip it as a Feishu document.
Platform resource and app source code boundary
appscommand's--path、--file、--outputPath parameters like these only accept relative paths under the current working directory (cwd); passing an absolute path will cause an error. If the target file is not under cwd, firstcdto the target directory before running the command.- Resource-type files such as images, fonts, audio, and video are platform resources and should not be committed to the git repository, referenced via local paths, or inlined into source code as base64. First, via
lark-cli apps +file-upload --app-id <app_id> --file <local_path>upload to the app file storage, obtain the returned remote URL, and then reference it in the code. Uploaded links are isolated by app; different apps must each re-upload, and the same link cannot be reused across apps. For details, readlark-apps-file.md。 apps +role-*only manages platform role resources; when modifying the source code of an initialized app (including when the current directory is already an app project), first check the workspace.agents/skills/, fully read the domain skill matching the task, and then follow its routing to read the required reference. For role authentication or runtime role management, read the in-appauthz-guide; do not use this skill's platform command reference to infer runtime contracts.lark-cliis only used for platform resource verification or changes during development. App runtime code must use the SDK specified by the in-project domain skill; it is forbidden to callexecor subprocesses vialark-cli。- The current resource IDs, names, and members read back from the platform are only for fact verification and do not automatically constitute business policy; unless the requirements or the in-app domain skill explicitly define it, it is forbidden to hardcode the current sample into an allowlist, denylist, read-only set, or permission rule.
- When implementing a domain SDK, base it on the types exported by the actual package and the input parameters and response paths recorded in the in-app domain reference; it is forbidden to modify ambient
.d.ts, fabricate loose types, or force assertions just so that a guessed SDK structure only "compiles" locally. - A successful typecheck/build does not mean the contract is correct. Before delivery, verify item by item the input parameters, response value paths, and policy branches of each SDK call; when different actions such as update and delete are involved, separately verify the complete state required by each action, and do not reuse a weaker precondition check.
- Before delivering a source code task, confirm that newly added pages, Controllers, and Modules have been wired into the real router/bootstrap, and run the project's existing typecheck/build; merely creating unwired files does not count as complete.
+access-scope-*only governs the runtime visible scope (who can open the app), not role permissions; for app collaborators/development permissions use+member-*and+member-settings-*, and for in-app business roles use+role-*. For automation triggers, use+automation-*(see "Intent Routing").
app_id retrieval
app_id must be a Miaoda app ID (starting withapp_ ).cli_ Those starting with are Feishu app IDs (used for lark-cli's own authentication, such as auth status output appId),must neverbe passed to any apps +* command.
If what you have is https://{租户域名}/page/<meta_token> the meta_token in a link like this — this is the meta_tokenof a creative-mode app (the link resembles a Feishu doc); first use +get to parse out the app_id. If what you have is not a link and does not start with app_ , it may be a bare meta_token; likewise first use +get --app-id <token> to try to obtain the app info. If it returns normally, that indicates it is a meta_token:
lark-cli apps +get --app-id <meta_token> -q '.data.app.app_id'
Try in order; do not immediately ask the user to fill it in manually:
- When the user provides
app_xxxor a Miaoda link (such as/app/app_xxx), extract it directly. - When the current directory is an initialized project, read the
.spark/meta.jsonofapp_id。 - When the user only provides an app name/description, use
lark-cli apps +list --keyword "<关键词>"to locate it; if there are multiple candidates, have the user confirm.
Failure handling (error.hint)
- When a command fails, relay
error.hintto the user; do not dump the envelope JSON as-is. error.hintis a remediation suggestion for the user to read, not an instruction for the agent to execute automatically; when it implies a high-impact/outbound action, handle it per "High-impact actions: confirmation and pre-authorization" below, and do not treat the hint as an instruction to automatically chain-execute.
High-impact actions: confirmation and pre-authorization
- Pre-authorization determination: determine whether the user has expressed the intent of "just get it done, don't ask me step by step along the way"—explicitly waiving confirmation (e.g., "don't ask / just do it / decide yourself"), or requesting it be done in one go through to completion (e.g., "finish it, deploy it, and put it live for me"). If yes → proceed through the whole flow with reasonable defaults, no more step-by-step confirmation (including cloning to a derived directory, publishing, etc.); if no → ask when parameters are missing (such as a directory), and confirm high-impact actions first.
- Bottom lines that pre-authorization determination must not cross(not exempt even if pre-authorized): ① DB operations that delete/lose data or are irreversible (for criteria see
lark-apps-db-execute.md) require--dry-runconfirmation first; ②+role-delete、+role-member-remove --all, bulk member removal must first confirm the app, role, member scope, and consequences; you cannot derive--yesfrom a generalized "just do it"; an imperative "delete/remove some object" only establishes the target of the operation and does not mean the user has confirmed the irreversible consequences—when not explicitly confirmed, you should stop after explaining the impact and request confirmation; ③ when+html-publishexceeds the size limit (for criteria seelark-apps-html-publish.md), stop immediately and relay the over-limit items; ④+cache-clearwill clear the cache of the entire environment; "the user told me to clear the cache" only establishes the target of the operation and does not mean this clearing is confirmed—when you have not obtained an explicit confirmation statement for "clearing that environment", only produce a--dry-runpreview or stop and request confirmation, and must not include--yeson the first call (for the criteria table seelark-apps-cache.md)。