Miaoda applications are user assets. By default, use --as user; general handling such as authentication, scope, exit-10, high-risk confirmation, and_notice is read-only, ../lark-shared/SKILL.md, do not copy it in this skill. Miaoda applications have two development paths:Local development(pull source code and write locally) / Cloud session(Miaoda AI generation).
Identity and authorization
Miaoda applications are the user's personal assets, 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 the original task may be interrupted and unnecessary device authorization may be triggered. 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 |
|---|---|---|
| Createnewapplication asset, get app_id | +create |
lark-apps-create.md |
| Find an existing app_id, filter applications by name | +list --keyword <name> |
lark-apps-list.md |
| Query details of a single application (type, name, release status, etc.) | +get --app-id <app_id> |
lark-apps-get.md |
| Change application name or description | +update |
lark-apps-update.md |
| HTML application / 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 release process) |
creative-design/creative-design.md |
| Legacy existing HTML applications (not managed by Git) continue to upload existing static artifacts | +html-publish(only compatible with the legacy pipeline; newly created html / creative mode / creative-design artifacts must not use it) |
lark-apps-html-publish.md |
Develop an existing application / 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 |
Read / analyze / summarize the content of a Miaoda application (any application mode, including the /page/<token> link of a creative mode application); only need one source code snapshot, do not do local development; or need to obtainan application shared with you by someone else's source code (you have no permission to its repository) |
+export(download the zip, then unzip and read the source code; do not configure git credentials, do not create a workspace). For a creative mode application, pass the /page/ link directly to --meta-token <token>, no need to first +get to exchange for app_id. 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 application environment variables (view/set/delete) | +env-list, +env-set, +env-delete |
lark-apps-env.md |
| Check online logs, traces, request count, error rate, latency, CPU, memory, PV/UV/visits | +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 traceability / 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 specifications for creating tables / altering tables / writing SQL | +db-execute |
lark-apps-db-execute.md(including "Platform SQL Specifications": 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 commit + git push, 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 |
"Application Collaborators and Collaboration Permission Settings" 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-application roles, 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 the application (after the development method has been determined to be 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 only once and is not persisted to disk) | +automation-list/get/create/update/enable/disable |
lark-apps-automation.md |
| View the reply messages of a certain turn in a session (including the current turn still being generated) / export the model reply from the previous turn ("what did this turn reply" "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 for the user identity; for pagination use --page-token) |
lark-apps-session-messages-list.md |
| External capability (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 needs 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 / whole-database sync / multi-table sync / batch task re-enable / operation-not-allowed", first read
lark-apps-db.mdthe Base data sync section, then check the app_id or handle authorization. Form a plan before acting:+db-sync-createhandles only one Base table at a time; whole-database/multi-table must be split into multiple single-table configurations and multiple preview/create calls; batch/import tasks are one-off 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, trends over the last hour/seven days", do not search the current workspace for monitoring files, and do not ask "where is the monitoring data". First resolve the application according to "app_id retrieval":
lark-cli apps +list --keyword "<应用名>" --as user; after obtainingapp_id, readlark-apps-observability.md, use+metric-list。 - request count + error count + latency: for request count/error count 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 provided a specific endpoint, also add--api <path-or-name>; do not invent group-by parameters. - PV/UV/visit count/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 app name, still first use
+list --keywordto resolve app_id; when setting the online environment and the user has already explicitly said "confirm/execute directly", call+env-set --environment online ... --yes, do not ask for confirmation again. In replies and log summaries mention only key / env / app, do not echo the real value; when a complex value needs to be passed, prefer@fileor stdin. - Delete environment variables:
+env-deleteis a destructive operation. Unless the user has already explicitly confirmed in the same turn the deletion of this app/env/key, first confirm with the user the app, environment, key, and consequences of deletion; after confirmation add--yes. Do not automatically continue the deletion just because authentication failed/re-login completed; the confirmation threshold must be preserved.
App collaborators and collaboration permission settings
This group of commands manages the development collaborators and collaboration policy of a Miaoda app; it is not equivalent to the runtime access scope of +access-scope-* , nor equivalent to the in-app business roles of +role-* . All commands use app_... app ID and --as user. Do not read or judge app_type to predetermine the support 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 app, members/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 member removal still executes the "prohibited pre-authorization determination bottom line"; one cannot derive--yes。- from a generalized "just do it". When adding, updating, or removing members, an explicitly provided matching external ID type must be given; 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. You can also use--role view|edit|full_accessto filter.+member-listreturns all direct collaborators of the app at once, with no pagination parameters provided; you can use--member-typeand--roleto narrow the result scope.- The member response does not include app details. When the name, type, or publish status is needed, call
+get --app-id <app_id>separately; do not expect the member pagination to repeatedly returnapp。 - When subtype
feature_not_available(OpenAPI code3340005is received; direct-connect service may be40005), immediately stop CLI automation, do not switchapp_type, and do not attempt to bypass it with 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_inviteis only read in the response of+member-settings-get, and cannot be set independently; it followsexternal_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 from the response of+member-settings-get. 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 (determine this step before entering intent routing)
Create new must first define app_type anddevelopment methodtwo orthogonal things; for modifying an existing one, first identify the app according to "app_id retrieval"; if it cannot be identified, ask the user, do not arbitrarily +create. Development method (local vs cloud) depends only on the user's preference for "who writes the code," and is unrelated to application complexity or whether a database is needed.
Three app_type boundaries(first determine "whether data needs to be stored on the server," then determine "purely display or interactive"):
| Signal | Determination |
|---|---|
| Includes database / backend persistence: login / CRUD / signup·voting·standup storing records / multi-person collaboration / generically called "system·tool" and explicitly requires data storage | app_type=full_stack |
| Purely static display (material 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 publishing process) |
| Has JS interaction but no database (frontend application for people to "use"): interactive prototype / SPA / form validation / dynamic calculation / calling external APIs / generically called "tool·system" but data storage is not explicitly required | app_type=frontend(Default tendency: when the user does not explicitly raise a database requirement, default to guiding frontend, do not default to full_stack) |
| Ambiguous type (especially unclear "whether data needs to be stored") | Follow-up question, with wording leaning toward frontend, e.g.: "This looks like a frontend application. Do you need to save data?"; after confirming data storage is needed, switch to full_stack; after confirming purely display, switch to html |
| 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 / do 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 .spark/meta.json project |
Directly continue locally and route by intent; no need to ask or determine cloud |
| Modify existing + has cloud preference | Cloud session; no preference expressed and not a local project → default local; if uncertain, ask first |
Type upgrade:frontend When the application later needs database/backend capabilities, the local CLI does not provide type upgrades; guide the user to a cloud session (open https://miaoda.feishu.cn/app/{app_id}), and describe the backend requirement in natural language (e.g. "add login and data storage to this application") to trigger the upgrade, with no special instruction needed.
Publishing-state guardrails
- Publishing intent determination: the user wants "accessible / online / share / new link / go live" = publishing intent; first follow the publishing chain, confirm completion, then provide the link.
+release-createThe release reason for is handled based on the application type: creative modehtmldoes not require a release reason, and the command must not pass--apply-reason;frontend/full_stackfirst loadlark-apps-release-create.md, generate the reason and incorporate it into the existing release confirmation, and pass in the same confirmed reason via the command.+release-gethas not yet returnedfinished/failed, and when it returnscurrent_node_info.current_status=PENDING(the top level may bepublishingorpending), immediately loadlark-apps-release-get.md, stop polling, and inform that the current user is waiting for the approval owner to handle it; do not assume that the current user orsubmitted_byis the approver. A terminal state takes precedence over a possibly lingering PENDING node.+release-createor+release-getOnly when the server-side error explicitly states that the client version is too old or requires an upgrade should you suggest executinglark-cli updateand then retry the original command (the query still uses the samerelease_id). Do not hardcode or guess a minimum version, and do not use--helpfor capability prechecks;X-Cli-Versionis uniformly carried by CLI requests and is not authentication information, and this workflow does not add a CLI version gate.- Completion ≠ release: the cloud session completing /
+list is_published=truedoes not mean the latest content has been deployed. - Development-state link
https://miaoda.feishu.cn/app/{app_id}(full_stack / frontend applications): the entry point for entering the application editing/development state, managing and continuing to develop the application, and also the entry point for upgrading frontend to full_stack (cloud session). For creative mode (html) applications, the development state and the release state are the same link, so there is no need to additionally provide a development-state link. - Source of the release-state link:
+release-getpollingfinishedgivesonline_url/failedgiveserror_logs(html / frontend / full_stack uniformly use+release-get)。 - The main workflow for html applications is the creative mode development approach: according to
lark-apps-local-dev.mdinitialize the repository, produce HTML and related files in the repository, and release and deploy through git commit / git push /+release-create/+release-get. When any git operation (clone / pull / push) reports an error, first executelark-cli apps +git-credential-init --app-id <app_id> --as userto refresh the local Git credentials, then retry the original git command. If refreshing the credentials also fails,stop and report to the user: the original git error, the reason the credential refresh failed, and whether it may be caused by a limitation of the current environment (operating system, sandbox) (such as macOS Keychain being unavailable in the sandbox, a Linux encrypted file directory not being writable, etc.). Do not switch to+html-publish, and do not treat+html-publishas a fallback for the local development workflow. - The link format for creative mode (html) applications is
https://{租户域名}/page/{meta_token},the development state and the release state are the same link(unlike full_stack applications, where the two are separate). This link resembles a Feishu document link.+get --app-id <meta_token>can obtain application information (includingapp_id),+get --app-id <app_id>can obtainmeta_token. When you see a/page/xxxlink, it is a Miaoda creative mode application; do not treat it as a Feishu document and skip it; when the user wants to understand / summarize the content of this application, directly+export --meta-token <token>export the source code to read it.
Boundary between platform resources and application source code
appscommand's--path、--file、--outputand other path parameters only accept relative paths under the current working directory (cwd); passing an absolute path will report an error. If the target file is not under cwd, firstcdto the target directory and then execute 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 by local paths, or inlined into the source code as base64. First, through
lark-cli apps +file-upload --app-id <app_id> --file <local_path>Upload to app file storage, obtain the returned remote URL, then reference it in code. Uploaded return links are isolated by app; different apps must each upload separately and cannot reuse the same link 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, then follow its routing to read the required reference. For role authentication or runtime role management, read the in-appauthz-guide, and do not use this skill's platform command reference to infer runtime contracts.lark-cliis only 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 invokeexecor 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 otherwise, it is forbidden to hardcode the current sample into an allowlist, denylist, read-only set, or permission rule.
- When implementing the domain SDK, base it on the types actually exported by the 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 to make the guessed SDK structure merely "compile 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 involving different actions such as update and delete, verify separately 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 connected to the real router/bootstrap, and run the project's existing typecheck/build; only creating unconnected files does not count as complete.
+access-scope-*only manages 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 please use+automation-*(see "Intent Routing").
app_id retrieval
app_id must be a Miaoda app ID (starting withapp_ ).cli_ Those starting with auth status are Feishu app IDs (used for lark-cli's own authentication, such as the appId),output bymust never be passed to any apps +* command.
If what you have is https://{租户域名}/page/<meta_token> a meta_token in a link like this — this is a creative-mode app's meta_token(the link looks like a Feishu doc). To only read / export source code you do not need app_id, directly +export --meta-token <meta_token>; for other commands that need app_id , first use +get to parse out 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 get app information; if it returns normally, it is a meta_token:
lark-cli apps +get --app-id <meta_token> -q '.data.app.app_id'
Try in order; do not demand that the user fill it in manually right away:
- 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
.spark/meta.jsonofapp_id。 - When the user only gives an app name/description, use
lark-cli apps +list --keyword "<关键词>"to locate it; if there are multiple candidates, ask the user to confirm.
Failure handling (error.hint)
- When a command fails, take
error.hintRelay it to the user; do not dump the envelope JSON as-is. error.hintIt is a remediation suggestion shown to the user, not an instruction for the agent to execute automatically; when it implies a high-impact/external 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, no need to ask me step by step along the way"—explicit waiver of confirmation (e.g., "don't ask / just do it / you decide"), or a request to carry it through to completion in one go (e.g., "deploy it to production when done and let me know"). Yes → the whole process proceeds with reasonable defaults, with no step-by-step confirmation (including cloning to a derived directory, publishing, etc.); no → missing parameters (such as a directory) should be asked about as needed, and high-impact actions should be confirmed first.
- Prohibited pre-authorization determination bottom line(not exempt even if pre-authorized): ① DB operations that delete/lose data or are irreversible (criteria see
lark-apps-db-execute.md) first--dry-runconfirm; ②+role-delete、+role-member-remove --all, bulk member removal must first confirm the app, role, member scope, and consequences, and--yescannot be derived from a generalized "just do it"; an imperative "delete/remove a certain object" only determines the operation target and does not mean the user has confirmed the irreversible consequences, and when not explicitly confirmed, one should stop after explaining the impact and request confirmation; ③+html-publishwhen the size exceeds the limit (criteria seelark-apps-html-publish.md), stop immediately and relay the over-limit items; ④+cache-clearwill clear the cache of the entire environment, and "the user told me to clear the cache" only determines the operation target and does not mean confirmation of this clearing—when an explicit confirmation statement for "clearing that environment" has not been obtained, only output the--dry-runpreview or stop and request confirmation, and must not include--yeson the first call (criteria table seelark-apps-cache.md)。