Install
openclaw skills install feishu-sheet-tabsCreate and organize multiple tabs (worksheets/pages) inside an existing Feishu sheet when the normal feishu_sheet API cannot create new worksheet tabs. Use when the user wants one spreadsheet split into categories/pages/tabs, asks for pagination inside a sheet, or wants separate worksheet tabs such as 总览 / Skills / Workflows / Templates / Content. Prefer this skill only after confirming feishu_sheet API lacks tab-creation support.
openclaw skills install feishu-sheet-tabsUse this skill to add worksheet tabs inside an existing Feishu sheet by browser automation when feishu_sheet API can create/read/write spreadsheets but cannot create worksheet tabs.
Current feishu_sheet API supports spreadsheet-level actions like:
It can target an existing sheet via sheet_id, but it does not expose a direct action for creating worksheet tabs/pages.
When the user explicitly wants tabs/pages inside one spreadsheet, switch to browser automation.
Before using browser automation, ensure all of the following:
Use browser with profile="chrome" if the user has attached the tab via OpenClaw Browser Relay.
Why:
Use profile="openclaw" only if it is already logged into Feishu.
Do not claim “can’t do it” without checking.
Confirm from tool docs / current tool signature that feishu_sheet has no add_sheet / create_worksheet / add_tab action.
Use browser automation to open the spreadsheet.
Feishu Sheets exposes internal JS objects on the page. In practice, these were found useful:
window.spreadwindow.spreadAppRelevant methods discovered from runtime introspection:
spread.addSheet(name)spread.renameSheet(sheetId, name)spread.copySheet(...)spread.moveSheet(...)spread.hideSheet(...)Use page evaluation to inspect current sheets before mutation.
Pattern:
window.spread.sheets.map((s,i)=>({
i,
id: s.id?.() ?? s._id ?? s.sheetId ?? null,
name: s.name?.() ?? s._name ?? null
}))
Typical pattern:
Sheet1 → 总览spread.addSheet(name)For example:
feishu_sheet writeAfter tabs exist and their sheet_ids are known, return to feishu_sheet for structured writes. This is more stable than trying to type cell-by-cell in browser automation.
For spreadsheet:
https://bytedance.larkoffice.com/sheets/Bf6qsMV9fhqrD6tPE6TcQhF7nEeThe following sequence worked:
window.spreadspread.addSheet and spread.renameSheetSheet1 to 总览SkillsWorkflowsTemplatesContentfeishu_sheet write with returned sheet ids to populate each tabfunction protoMethods(obj,name){
if(!obj) return [];
const out=[];
let p=Object.getPrototypeOf(obj);
let depth=0;
while(p && depth<4){
for(const k of Object.getOwnPropertyNames(p)){
if(k==='constructor') continue;
if(/sheet|tab|workbook|insert|create|add|page|name|rename/i.test(k)) out.push(`${name}.${k}`);
}
p=Object.getPrototypeOf(p); depth++;
}
return [...new Set(out)];
}
async () => {
const spread = window.spread;
const results = [];
const current = spread.sheets.map(s => ({
id: s.id?.() ?? s._id ?? null,
name: s.name?.() ?? s._name ?? null
}));
const first = current[0];
if (first?.name === 'Sheet1') {
results.push(await spread.renameSheet(first.id, '总览'));
}
for (const name of ['Skills','Workflows','Templates','Content']) {
const names = spread.sheets.map(s => s.name?.() ?? s._name);
if (!names.includes(name)) {
results.push(await spread.addSheet(name));
}
}
return spread.sheets.map((s,i)=>({
i,
id: s.id?.() ?? s._id ?? null,
name: s.name?.() ?? s._name ?? null
}));
}
Prefer internal methods over brittle UI clicking
Clicking + in the UI was less reliable than runtime JS calls.
Do not assume a visible plus button is the right entry In this case, one nearby button turned out to be a template entry, not “new tab”.
Use browser only for the tab creation step
Once tabs are created, switch back to feishu_sheet write.
Inspect current ids before writing
New tabs get generated sheet_ids such as GxGIGa, 9dJYiB, etc. Use actual returned ids.
Avoid blind UI automation first Inspect runtime objects and methods before pixel-clicking.
Use this skill when the user says things like:
When done, report: