A thin CLI agent and TUI shell over Pi's SDK and lark-cli for Feishu (飞书) / Lark automation, skills, and workflows — long-term memory, skill authoring, and high-risk approval guards for Feishu deliverables.
English | 简体中文
Feishu Agent is a thin executable shell over Pi's public SDK and TUI for Feishu deliverables and lark-cli workflows. It is not a Pi fork or a general coding agent. Resource Isolation is not an OS sandbox.
Feishu Agent drives Feishu/Lark work through natural language, backed by the 28 official lark-cli skills (messaging, docs, calendar, Base, approvals, and more). Use it to:
- Send and manage messages — post to chats, reply in threads, upload files, and handle interactive cards as a Feishu bot (
lark-im); build a Feishu/Lark chat bot without writing integration code. - Automate documents and files — create and edit Feishu Docs (Docx), Sheets, Slides, and cloud-drive files (
lark-doc,lark-sheets,lark-slides,lark-drive). - Run workflow automations — summarize meetings and minutes, draft standup reports, and script multi-step Feishu workflows (
lark-workflow-*,lark-meeting,lark-minutes). - Manage calendar and approvals — check schedules, book meeting rooms, and process approval tasks (
lark-calendar,lark-approval). - Operate Bitable / Base — create tables, fields, records, views, and dashboards in Feishu Base (
lark-base). - Remember across sessions — optional, after
feishu install npm:pi-hermes-memory@0.9.10. Files stay under~/.feishu-agent/, not~/.pi/agent. - Author your own skills — encode repeatable Feishu workflows as private skills (
feishu-skill-maker). - Write technical notes that render well in Feishu — use the bundled LaTeX/XML guidance and process-report workflow templates.
- Extend with packages — add MCP servers, web access, and subagents through Pi-compatible extensions.
High-risk actions (deletes, revocations, /share) require explicit one-shot approval; ambiguous or chained destructive commands are blocked.
Feishu Agent runs as a CLI from source — it is not published to npm.
- Node.js ≥ 24
lark-cli— the official Feishu/Lark CLI, npm package@larksuite/cli. Install withnpm i -g @larksuite/cli, then runlark-cli authto log in solark-cli doctorpasses.Install
@larksuite/cli, not the unrelated placeholder package literally namedlark-clion npm.- Pi coding agent —
npm i -g @earendil-works/pi-coding-agent. Feishu reuses Pi's model credentials from~/.pi/agent/and disables its own/login, so authenticate a model with ordinarypifirst (pi authchecks readiness). Memory is not part of setup. Installpi-hermes-memorylater if you want it.MEM0_API_KEYis not required.
From a clone of this repository:
bash scripts/setup.shThe script builds and links Feishu, runs lark-cli auth login, asks you to log in with ordinary pi /login, then runs feishu init. It does not ask for a Mem0 key.
git clone https://github.com/Azhi-ss/feishu-agent.git
cd feishu-agent
npm install
npm run build
npm link # exposes the `feishu` binary (or run `node dist/src/cli.js` directly)Node 24 is the only supported runtime, locally and in CI; there is no second version to keep compatible.
npm run build
node --test dist/test/package-cli.test.js # select the file relevant to the change
npm test
git diff --checkAfter pulling a change that renames or deletes TypeScript files, clean generated
output before rebuilding: tsc does not remove obsolete JavaScript files, and
npm test discovers every dist/test/*.test.js. In particular, the test split
removes remote-bridge.test.ts and automation-trigger-recurring.test.ts; their
old compiled files must not run alongside their replacements.
node -e "require('node:fs').rmSync('dist', { recursive: true, force: true })"
npm run buildThe repository also contains skills/feishu-control/, a host-side bridge that lets another Pi-compatible Agent delegate work to feishu. It is not a Feishu Runtime Skill: do not put it under ~/.feishu-agent/skills/ and do not expect feishu init to install it.
After feishu is on PATH, install the bridge into a Pi host Agent:
npx skills add Azhi-ss/feishu-agent --skill feishu-control --global --agent pi --copyThe installer copies both SKILL.md and feishu-send into the host Agent's Skill directory. Then use /skill:feishu-control <task> or explicitly ask the Host Agent to use Feishu Agent. Review the Skill before accepting the install; it runs feishu with the current user's permissions.
A delegation can take several turns. Exit code 3 means Feishu Agent is waiting for the user, either with a question on stdout or with a high-risk confirmation request on stderr. The Host relays it, then continues the same session with the user's reply: feishu-send --session <id> "<reply>", where <id> comes from the Feishu Session: line on stderr. Reinstall the Skill after updating this repository so the Host gets the new protocol.
feishu init --model provider/model --thinking mediumInitialization creates private state and ten bundled Feishu Skills under ~/.feishu-agent/, requires an explicit authenticated Feishu model on fresh initialization, stores a supported Feishu-only thinking preference, runs lark-cli doctor under the invocation's selected profile, installs the pinned Feishu Remote Package, and synchronizes official lark-cli Skills. It does not install a memory package or ask for a memory identity. Re-running fills missing state and does not overwrite model, customized SYSTEM.md, edited Skills, or an existing local/npm Remote Package source. Use --reset-model or --reset-system for explicit replacement.
Feishu assembles local instructions in this order:
~/.feishu-agent/SYSTEM.md— base Feishu identity (built-in default if absent).~/.feishu-agent/SOUL.md— optional persona and collaboration style.~/.feishu-agent/USER.md— optional user background and stable preferences.<project>/.feishu-agent/AGENTS.md— Feishu-specific project instructions.<project>/AGENTS.md— shared project instructions.
Create the optional files yourself; missing or empty files are skipped. feishu init, including --reset-system, leaves them untouched. Only the Feishu Agent Home supplies SOUL.md and USER.md; project-local copies and other agents' profiles are ignored. Restart Feishu or use /reload in Interactive mode after editing. These files are included in model requests, so keep them concise and never store credentials in them. They describe context, not account authentication or permission grants.
feishu # Interactive Feishu Runtime
feishu -p "task" # one Print-mode turn
feishu -c # continue this Feishu Project's latest session
feishu -r # select a session in this Feishu Project
feishu --session <id> # resume an exact session in this Feishu Project
feishu --session <id> -p "reply" # continue that session with one Print-mode turn
feishu --lark-profile finance -p "task"Every Print run writes Feishu Session: <id> to stderr. Print exits 0 when the task is done, 3 when Feishu Agent is waiting for your answer or confirmation, and any other nonzero code on failure. In Print mode Feishu Agent asks through a Print-only ask_user tool: the question and numbered options go to stdout, and your reply continues the session with feishu --session <id> -p "...". To confirm a blocked destructive lark-cli write, continue the session with an explicit request such as "yes, delete doc X".
In Interactive mode, /find-skill <query> searches the public Skill index; selecting a result shows its source, install count, declared license, and private target path before confirmation. You can also use /find-skill install <owner/repo@skill-name> for an explicit result. Installation writes only to ~/.feishu-agent/skills/—never the real HOME's ordinary Pi global directories—and Print mode searches without waiting for install confirmation. /remote [start|stop|status] is provided by the independently published Feishu Remote Package (@azhi-ss/feishu-remote) to control the active session from mobile Feishu (see docs/remote-bridge.md). The package is transport only: ordinary Pi can install it with pi install npm:@azhi-ss/feishu-remote, and does not gain Feishu Agent skills or policy.
Normal Interactive exit rewrites Pi's generic resume line to To resume this Feishu session: feishu --session <id>; copy that command to resume the exact session. Use feishu -c for the latest session or feishu -r to choose one. If feishu is not on PATH, set FEISHU_RESUME_COMMAND to the full executable path. Do not resume Feishu sessions through ordinary pi --session-dir ... --session ..., because that bypasses the Feishu Runtime boundary.
The Feishu Runtime disables Pi's built-in startup network checks, so you will never see Pi's pi update version notice or pi update --extensions package-update notice: upgrading Pi or extensions stays a deliberate, out-of-band action.
Only Interactive and text Print modes are supported. JSON and RPC are intentionally absent.
Scheduling is no longer built into the Feishu Runtime. The independent package
@azhi-ss/feishu-automation contains the
CLI, background Trigger and Skill. It is not auto-installed by feishu init and
has not been published to npm. Build and explicitly opt in from a local checkout:
npm run build --workspace @azhi-ss/feishu-automation
feishu install /absolute/path/to/feishu-agent/packages/feishu-automationThe Skill invokes its bundled CLI by absolute path. For manual use below, replace
feishu-automation with node /absolute/package/path/dist/cli.js unless its npm
bin is installed on PATH. Installing never starts a service or runs tasks.
CLI migration: feishu-automation replaces the removed core subcommand
feishu automation.
See the package README for current commands, safe migration and uninstall steps.
The Skill presents the full plan and waits for approval before saving or editing.
For example: “Every weekday at 09:00 Beijing time, send an ordinary bot message to this conversation and append a summary as me to this existing document. Show me the full plan first.” Saving the approved plan does not activate the background service or make a trial write; approve those separately.
You can also prepare a task file and use the same CLI directly:
feishu-automation add --name reminder --at 2030-06-01T09:00 \
--prompt-file task.md --catch-up 2h --timeout 10m --yes
feishu-automation list
feishu-automation show reminder
# Alternative schedules (use distinct names and review each complete plan):
# --cron '0 9 * * 1-5' # weekday 09:00 in the saved timezone
# --every 90m # elapsed 90 minutes, NOT a cron minute-field step
feishu-automation serve # foreground: keep this process alive
# In another terminal, an explicit separate attempt:
feishu-automation run reminder--yes attests that the caller reviewed and confirmed the plan. Without it,
interactive creation asks for confirmation; noninteractive creation fails promptly.
Offset-less --at values use the saved IANA timezone (--tz, default
Asia/Shanghai); an explicit offset identifies an absolute instant. Timing is
minute-level, never before the due instant. The default two-hour lateness window
is inclusive; an unstarted one-shot beyond it becomes expired, not failed or
deleted. Definitions, run output, and per-run scratch areas live in ~/feishu-jobs,
separate from the legacy Briefing workspace.
Cron uses numeric five-field syntax (wildcards/lists/ranges/steps); restricted
calendar day and weekday combine with OR. No seconds or systemd calendar syntax.
Recurring catch-up defaults to 2h, coalescing to the latest eligible occurrence,
or use --no-catch-up to skip missed minutes. Fixed intervals begin one interval
after first enablement, keep that anchor across runs/restarts/pause/resume, and
establish a new anchor only on an approved interval change. Default timeout is
10m from actual execution. Failures never cause automatic whole-job retry.
feishu-automation update reminder --at 2030-06-01T09:05 --yes # after renewed approval
feishu-automation pause reminder # future dispatch only; current run continues
feishu-automation resume reminder # no replay of intentionally paused time
feishu-automation cancel reminder # stop current run; earlier writes are not rolled back
feishu-automation rm reminder # disable dispatch, retain task/history and name
feishu-automation rm reminder --purge --yes # explicit irreversible artifact removalUpdates retain unspecified values; the old plan stays active during confirmation
unless explicitly paused, and an in-flight run retains its original snapshot.
Removal refuses active runs: clarify pause versus cancel first. Ordinary rm is
not purge; only purge accepts --yes. Inspect show for recent outcomes and run
records (logs retained 30 days). A retained removed name cannot be silently reused.
Only one Trigger (foreground or background) admits scheduled work in a managed workspace. It shares
same-job exclusion and a two-run capacity limit with independent manual callers.
Waiting never extends the original lateness deadline. Every run is a fresh
FEISHU_UNATTENDED=1 Print child without Mem0, using the saved Lark profile and
normal tools/guards. Scheduled occurrences are consumed before work is released;
restart or clock rollback does not replay failed, timed-out, interrupted/unknown,
or overlap-skipped occurrences. Runner completion is not proof of Feishu
business delivery. Manual runs do not consume/re-arm one-shots, change expiry or
shift recurring timing, and may repeat external effects. In particular, a manual
run of a future one-shot leaves its scheduled occurrence eligible, so it may
write again at the scheduled time. Paused/completed/expired retained jobs can be
run manually; removed jobs cannot. Inspect receipts and logs: partial work,
failed access, cancellation and unknown outcomes are not rolled-back writes or
proof of delivery/non-delivery.
Ctrl-C stops foreground admission and bounds only Trigger-owned children. Independent manual runs remain supervised by their own callers and continue occupying capacity. For independent background execution, explicitly run:
feishu-automation start # launchd on macOS; systemd --user on Linux/WSL
feishu-automation status # live Trigger owner, not just an installed artifact
feishu-automation stop # disable restart; retain jobs/history and manual runsStart checks local prerequisites and installs only the dedicated managed service. Its configuration contains resolved executable paths and a minimal nonsecret HOME/PATH environment; credentials remain in their existing local stores. After moving/upgrading Node or this package, explicitly run start again to refresh it. A failed setup restores the previous configuration in a stopped state; inspect status and the named user service before retrying a reported rollback failure.
The host and Trigger must stay alive: sleep, power-off, WSL shutdown, and logout
without an active user manager are not solved here. If no user manager is
available, use foreground serve; no root, linger, login, or wake changes are made.
Normal Interactive/Print/init never install, start, wait for, or probe the service.
Keep one active host per job. Portable definitions do not provide automatic
synchronization, failover or cross-host duplicate suppression. Stop scheduling on
the old host before enabling a moved job elsewhere.
Business policy is prompt-only: ordinary messages to fixed conversations as bot, and append-only updates to fixed existing documents as user. No target or identity fallback, replacement documents, automatic group joining, destructive edits, approvals, member/permission changes or urgent escalation. Normal tools remain available: model mistakes and prompt injection can still cause out-of-plan writes. This is not a sandbox or a hard per-target permission boundary. Existing high-risk guards and credential protections remain unchanged. Scripted fake-model tests prove the workflow and policy reach the model, not universal compliance.
Package installation never migrates the existing Briefing; disable its old timer explicitly before scheduling the same deliverable here. No Sweep/Alert is enabled. Corrupt state is diagnosed and retained for inspection, never guessed safe to replay.
feishu init sets up a minimal runtime plus ten bundled private Feishu Skills. Nothing else is preloaded beyond:
| Capability | Source | Notes |
|---|---|---|
| Long-term memory | optional pi-hermes-memory (not installed by feishu init) |
Files under ~/.feishu-agent/. TUI shows ● mem when that extension is loaded, otherwise ○ mem off. Leftover @mem0/pi-agent-plugin is not loaded |
| Remote Bridge | @azhi-ss/feishu-remote (pinned npm package, auto-installed by feishu init) |
Phone control of the active session; transport only — not Feishu Skills, Mem0, or high-risk approval. Ordinary Pi may run pi install npm:@azhi-ss/feishu-remote. |
| Core policy guard | built-in (hidden feishu-core-policy extension) |
High-risk lark-cli --yes approval gate, blocked /share /import /login /logout |
| Skill authoring | built-in feishu-skill-maker skill |
Guide for creating new Feishu Skills |
| Skill discovery and private installation | built-in /find-skill command and feishu-find-skill skill |
Reuses the skills.sh index and npx skills staging; final files go only to ~/.feishu-agent/skills/, never ~/.agents/skills or ~/.pi/agent/skills |
| Technical-note formula rendering | bundled feishu-latex-rendering skill |
Markdown/LaTeX to Feishu XML guidance, nesting rules, escaping checklist, and conversion example |
| Process-report workflow | bundled process-optimization-biweekly skill |
Sanitized reusable template for source collection, lifecycle-based progress writing, and Feishu document updates |
| Official Feishu skills | read-only cache from the local lark-cli (28 skills: lark-im, lark-doc, lark-calendar, …) |
Keyed by CLI version, synced lazily; refresh with feishu skills sync |
| Core tools | read edit write bash grep find ls |
Third-party packages cannot replace these names |
| Default theme | bundled breezy-ocean (MIT, from awesome-pi-themes) |
Applied as the one-shot default; pick another any time in /settings |
The default TUI theme (breezy-ocean) is bundled and applied automatically; switch it in /settings. Prompt templates are not bundled; additional themes and templates load through packages as needed.
Startup listing is Pi's. Set "quietStartup": true in ~/.feishu-agent/settings.json (or Quiet startup in /settings) to hide Context, Skills, Prompts, Extensions, and Themes. Optional "feishuStartup" redraws the banner and a short list instead:
"feishuStartup": { "banner": true, "skills": "count", "sections": ["context", "skills", "prompts", "extensions", "themes"] }skills is names, count, or hide. banner: false drops the bird header. Add "tasks" to sections to list unfinished Feishu task names from ~/.feishu-agent/tasks.json (a short date follows the name only when that task has a due date; at most five lines, with further names collapsed into +N). Interactive startup pulls a fresh list while the rest of the TUI loads. /new and /reload do not. Pull again with /tasks, or feishu tasks refresh. Omit feishuStartup to keep the default banner only.
Pi-compatible extension packages install with feishu install npm:<package>. Feishu does not auto-install any of these — opt in per machine/project. For npm packages, verify the current version with npm view <package> before pinning. The Feishu subagents fork uses the local installation documented below.
| Package | What it adds | When to install |
|---|---|---|
pi-web-access |
Web search, URL fetching, GitHub repo cloning, PDF extraction, YouTube/video understanding; pluggable backends (Tavily, Firecrawl, Jina, Exa, Gemini, Kimi, SearXNG, …) | Most recommended — when Feishu needs to read online docs, look up Feishu API references, or fetch a link |
pi-mcp-adapter |
Use MCP (Model Context Protocol) servers as tools | You already have MCP servers (or want a specific vendor's MCP integration) |
| Feishu subagents fork | Native child delegation and scripted workflows with Feishu resources and policy | Long, parallelizable Feishu tasks; install the adapted local package |
pi-background-tasks |
Durable background shell tasks, read-only delegated agents, attested local Pi runs | Letting long-running lark-cli jobs survive the session |
pi-hermes-memory@0.9.10 |
Persistent memory, session search, and secret scanning | The memory package for Feishu. Its docs say ~/.pi/agent; Feishu stores it under ~/.feishu-agent/ |
feishu install npm:pi-web-access # recommended, global
feishu install -l npm:pi-mcp-adapter # current project only
feishu list
feishu remove /absolute/path/to/pi-subagents-feishu
feishu update --extensions
feishu config set npm:pi-web-access extensions off
feishu config -l set ./local-package skills off
feishu skills syncNot recommended for Feishu: packages from the @oh-my-pi/* ecosystem — those target the separate oh-my-pi/omp agent, not pi-coding-agent, and are not compatible with this runtime.
Global packages live below ~/.feishu-agent/; project packages live in <git-root>/.feishu-agent/. Manifest Extensions, Skills, Prompts, and Themes load with Pi package filtering semantics; omitted types load all, [] loads none, glob exclusions narrow, and exact +path/-path entries force inclusion/exclusion. feishu config starts in Feishu global settings and feishu config -l starts in project Feishu settings; feishu config [ -l ] set <source> <resource> <on|off> is the scriptable equivalent for durable resource toggles. The isolated UI child prevents Pi's config exit behavior from terminating an embedding host. Official and private Feishu Skills never scan ordinary Pi, .pi, .agents, Codex, or Claude skill roots. Before installing a third-party Skill, /find-skill displays its declared license (or clearly says it is missing); that declaration is not legal clearance for the Skill or any third-party material it references, so review it manually.
Feishu Agent reuses existing lark-cli state without copying tokens. Personal-resource operations use explicit --as user; Bot identity is only used when requested or required. The high-risk guard is intentionally minimal: a destructive lark-cli command (delete/remove/revoke/withdraw) carrying --yes is allowed only when the user's current-turn message explicitly asks for a destructive action (e.g. “删除/delete the document”); otherwise the run is blocked with actionable guidance. Without --yes, TUI mode passes through to lark-cli's own confirmation prompt, while Print mode fast-fails instead of hanging. Approval is turn-scoped, not one-shot; no target/identity metadata is probed. This runtime guard is not an OS security boundary.
Feishu has no long-term memory. It does not capture turns, recall earlier facts, or contact a memory service. A Feishu Session file is the only continuity between turns.
The release suite compiles the real CLI and exercises it only with temporary homes/projects, PTYs, and loopback fake model, Mem0, Lark, and npm services—never real network endpoints or user credentials. It verifies:
- a fresh HOME can run
feishu init, an immediate Print turn, a mounted Interactive turn, a fake personal Lark command with explicit--as user, and project-local sessions; - hostile ordinary Pi home/project
.piand.agentsresources stay unloaded, conflicting package core tools are rejected with warnings, and a replacement prompt or custom editor cannot replace the base identity or outer command guard; - two projects keep sessions, private Skills, package settings, and loaded package Skills independent;
- official Skill fallback emits a visible warning while core file, Bash, Lark, Print, and Interactive work continues;
- recursive artifact and diagnostic scans reject copied Lark tokens, and raw tool output remains local to sessions.
Resource Isolation prevents automatic loading from other agents; it does not restrict filesystem, subprocess, extension, or network permissions. Installed Feishu Package extensions execute with current-user permissions. Feishu Agent does not copy Lark/model tokens, support session sharing/import, or accept unrelated general software-development work; use ordinary pi for that.