
Feishu Pm
- 2 installs
- 20 repo stars
- Updated April 11, 2026
- autogame-17/feishu-skills
feishu-pm is a Claude skill that manages project tasks and records in Feishu Bitables, adding tasks and listing progress from the CLI.
About
feishu-pm manages project tasks and records in Feishu Bitables directly from the CLI. It lists records with view and limit filters and adds tasks with a title, description, and priority. Developers use it when an agent needs to track project progress in a Feishu Bitable. Field mapping is currently optimized for an Iter 11 project structure and can be edited for other projects.
- Manages project tasks and records in Feishu Bitables from the CLI
- List tasks (with view/limit filters) and add tasks with title and priority
- Field mapping is editable for projects beyond the default Iter 11 layout
Feishu Pm by the numbers
- 2 all-time installs (skills.sh)
- Ranked #2,409 of 3,280 Productivity & Planning skills by installs in the Skillselion catalog
- Data as of Jul 28, 2026 (Skillselion catalog sync)
feishu-pm capabilities & compatibility
Free skill; requires a Feishu app credential pair (FEISHU_APP_ID / FEISHU_APP_SECRET) via feishu-common.
- Capabilities
- feishu task · feishu doc
- Works with
- notion
- Use cases
- project management
What feishu-pm says it does
Project Management skill for Feishu Bitables. Add tasks, list records, and track progress directly from the agent.
Manage tasks and project records in Feishu Bitables directly from the CLI.
npx skills add https://github.com/autogame-17/feishu-skills --skill feishu-pmAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2 |
|---|---|
| repo stars | ★ 20 |
| Last updated | April 11, 2026 |
| Repository | autogame-17/feishu-skills ↗ |
What it does
List and add project tasks in a Feishu Bitable from the CLI to track progress.
Who is it for?
Adding and listing project tasks with priorities in a Feishu Bitable from an agent.
Skip if: Task management in Jira, Notion, or platforms other than Feishu Bitables.
When should I use this skill?
An agent needs to add or list tasks and track project progress in a Feishu Bitable.
What you get
Tasks are added and project records listed in a Feishu Bitable directly from the CLI.
- Listed Feishu Bitable records or a newly added task
By the numbers
- Default list limit of 20 records
- 2 core commands (list, add)
Files
Feishu Project Manager (PM)
Manage tasks and project records in Feishu Bitables directly from the CLI.
Prerequisites
- Install
feishu-commonfirst. - This skill depends on
../feishu-common/index.jsfor token and API auth.
Usage
List Tasks
node skills/feishu-pm/index.js list --app <BITABLE_TOKEN> --table <TABLE_ID>Options:
--view <id>: Filter by View ID.--limit <n>: Limit number of records (default 20).--json: Output raw JSON instead of markdown table.
Add Task
node skills/feishu-pm/index.js add --app <BITABLE_TOKEN> --table <TABLE_ID> --title "Fix Bug #123" --priority "High"Options:
--desc <text>: Task description.--priority <text>: Priority level (e.g. "High", "Medium", "Low").
Notes
- Currently optimized for the "Iter 11" project structure (
需求,需求详述,优先级). - Edit
index.jsto customize field mapping for other projects.
const { program } = require('commander');
const { fetchWithAuth, getToken } = require('../feishu-common/index.js');
// --- Helper: Bitable API ---
async function listRecords(appToken, tableId, viewId = null, limit = 20) {
let url = `https://open.feishu.cn/open-apis/bitable/v1/apps/${appToken}/tables/${tableId}/records?page_size=${limit}`;
if (viewId) url += `&view_id=${viewId}`;
const res = await fetchWithAuth(url);
const data = await res.json();
if (data.code !== 0) throw new Error(`List failed: ${data.msg}`);
return data.data.items || [];
}
async function addRecord(appToken, tableId, fields) {
const url = `https://open.feishu.cn/open-apis/bitable/v1/apps/${appToken}/tables/${tableId}/records`;
const res = await fetchWithAuth(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ fields })
});
const data = await res.json();
if (data.code !== 0) throw new Error(`Add failed: ${data.msg}`);
return data.data.record;
}
// --- Smart Formatter ---
function formatRecords(records) {
if (!records.length) return "No records found.";
// Auto-detect key fields based on common names
// Priority: Title > Priority > Status > Assignee
const fieldMap = {
title: ['需求', 'Title', 'Name', '任务名称', 'Task'],
priority: ['优先级', 'Priority', 'P'],
status: ['状态', 'Status', 'Stage'],
assignee: ['责任人', 'Assignee', 'Owner', '开发执行人员']
};
// Find actual field names
const sample = records[0].fields;
const keys = Object.keys(sample);
const map = {};
for (const [key, candidates] of Object.entries(fieldMap)) {
map[key] = candidates.find(c => keys.includes(c));
}
const headers = ['ID', 'Title', 'Priority', 'Status', 'Assignee'].filter(h =>
h === 'ID' || map[h.toLowerCase()]
);
let md = `| ${headers.join(' | ')} |\n| ${headers.map(() => '---').join(' | ')} |\n`;
for (const r of records) {
const row = [r.record_id];
if (map.title) row.push(String(r.fields[map.title] || '').substring(0, 30));
if (map.priority) row.push(String(r.fields[map.priority] || ''));
if (map.status) row.push(String(r.fields[map.status] || ''));
if (map.assignee) {
// Handle User object (usually an array of objects)
const val = r.fields[map.assignee];
if (Array.isArray(val)) {
row.push(val.map(u => u.name || u.id).join(', '));
} else {
row.push(String(val || ''));
}
}
md += `| ${row.join(' | ')} |\n`;
}
return md;
}
// --- CLI ---
program
.command('list')
.description('List records from a Bitable')
.requiredOption('--app <token>', 'App Token (bitable token)')
.requiredOption('--table <id>', 'Table ID')
.option('--view <id>', 'View ID')
.option('--limit <n>', 'Limit', 20)
.option('--json', 'Output raw JSON')
.action(async (opts) => {
try {
const records = await listRecords(opts.app, opts.table, opts.view, opts.limit);
if (opts.json) {
console.log(JSON.stringify(records, null, 2));
} else {
console.log(formatRecords(records));
}
} catch (e) {
console.error(e.message);
process.exit(1);
}
});
program
.command('add')
.description('Add a task/record')
.requiredOption('--app <token>', 'App Token')
.requiredOption('--table <id>', 'Table ID')
.requiredOption('--title <text>', 'Task Title')
.option('--desc <text>', 'Description')
.option('--content <text>', 'Content (alias for --desc)')
.option('--priority <text>', 'Priority (e.g. "Important")')
.action(async (opts) => {
try {
// Alias mapping
if (opts.content && !opts.desc) opts.desc = opts.content;
// Hardcoded mapping for "Iter 11" style for now, but extensible
const fields = {
'需求': opts.title
};
if (opts.desc) fields['需求详述'] = opts.desc;
if (opts.priority) fields['优先级'] = opts.priority;
const rec = await addRecord(opts.app, opts.table, fields);
console.log(`Created Record: ${rec.record_id}`);
} catch (e) {
console.error(e.message);
process.exit(1);
}
});
program.parse(process.argv);
{
"name": "feishu-pm",
"version": "1.0.0",
"description": "Project Management skill for Feishu Bitables",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"commander": "^9.0.0"
}
}
Related skills
FAQ
Can I use it for any Bitable schema?
It is optimized for the Iter 11 structure, but you can edit index.js to customize the field mapping for other projects.
How do I limit how many records are returned?
Pass --limit <n> to the list command; the default is 20 records.