rootr-cli 0.17.3 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +107 -3
- package/README.md +86 -4
- package/bin/rootr.js +688 -13
- package/lib/client.js +250 -26
- package/lib/credentials.js +20 -2
- package/lib/mcp-tools/ask.js +6 -1
- package/lib/mcp-tools/attachments.js +31 -11
- package/lib/mcp-tools/booking.js +403 -0
- package/lib/mcp-tools/databases.js +490 -20
- package/lib/mcp-tools/documents.js +183 -16
- package/lib/mcp-tools/forms.js +63 -1
- package/lib/mcp-tools/logs.js +1 -1
- package/lib/mcp-tools/misc.js +9 -3
- package/lib/mcp-tools/pages.js +31 -7
- package/lib/mcp-tools/presentations.js +36 -12
- package/lib/mcp-tools/public.js +4 -1
- package/lib/mcp-tools/recordings.js +39 -15
- package/lib/mcp-tools/shared.js +28 -0
- package/lib/mcp-tools/workspaces.js +155 -77
- package/lib/mcp.js +3 -0
- package/lib/resolve.js +43 -1
- package/package.json +1 -1
package/README.ko.md
CHANGED
|
@@ -138,6 +138,22 @@ rootr append /notes/log.md --file ./chunk.md
|
|
|
138
138
|
`--heading`을 지정하면 해당 헤딩 섹션 끝에 추가되고, 없으면 문서 끝에 추가됩니다.
|
|
139
139
|
append는 전체 내용을 다시 쓰지 않으므로 다른 프로세스와 동시에 써도 충돌하지 않습니다.
|
|
140
140
|
|
|
141
|
+
### 문서 안에 표 끼워 넣기 (embed) — 노션의 "링크된 데이터베이스"처럼
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
rootr embed /회의/주간회의.md /프로젝트/업무 표
|
|
145
|
+
rootr embed /회의/주간회의.md /프로젝트/업무 표 --heading "## 업무"
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
문서 안에 표·스프레드시트·발표자료·화이트보드·폼·녹음·로그·이슈 트래커를 **살아 있는 채로**
|
|
149
|
+
보여 줍니다(복사본이 아니라 표를 고치면 문서에도 바로 보입니다). 편집기의 "끼워 넣기" 블록과 같습니다.
|
|
150
|
+
|
|
151
|
+
- MCP: `rootr_embed_node` (`target` = 문서, `node` = 끼울 것 — 둘 다 경로나 id)
|
|
152
|
+
- REST: `POST /v1/documents/:id/embeds` 에 `{ "node": "/프로젝트/업무 표" }`
|
|
153
|
+
- 직접 쓰기: `rootr_write`·`rootr_append` 내용에 `[[embed:/프로젝트/업무 표]]` 한 줄. 저장할 때 id 로
|
|
154
|
+
바뀌고, 없는 경로나 볼 권한이 없는 것이면 400 으로 거절하고 아무것도 쓰지 않습니다.
|
|
155
|
+
- 스캐폴딩: 같은 트리에서 만드는 표는 이름으로 — `[[embed:업무 표]]`
|
|
156
|
+
|
|
141
157
|
### 텍스트 치환 (edit)
|
|
142
158
|
|
|
143
159
|
```bash
|
|
@@ -209,6 +225,8 @@ rootr config # 등록된 키 목록 확인
|
|
|
209
225
|
|
|
210
226
|
프로그램(API 키·MCP) 호출 중 **조회 계열**(`docs:read`/`graph:read`/`ask`)에만 한도가 있습니다.
|
|
211
227
|
쓰기·업로드는 제한하지 않습니다.
|
|
228
|
+
공개 주소(`rootr.io/p/{slug}`)를 `rootr_read` 로 읽는 것도 조회 1회로 셉니다(남의 워크스페이스 공개 문서 포함). 같은 주소를
|
|
229
|
+
브라우저로 여는 것은 세지 않습니다.
|
|
212
230
|
|
|
213
231
|
| 플랜 | 한도 |
|
|
214
232
|
| --- | --- |
|
|
@@ -221,6 +239,22 @@ rootr config # 등록된 키 목록 확인
|
|
|
221
239
|
업그레이드 링크가 담긴 안내가 나옵니다. 응답 헤더로도 확인할 수 있습니다
|
|
222
240
|
(`X-RateLimit-Remaining`, `X-RateLimit-Reset`, `X-RateLimit-Window`).
|
|
223
241
|
|
|
242
|
+
#### 처음 옮겨 올 때: 이관 유예 72시간
|
|
243
|
+
|
|
244
|
+
옮겨 오는 일은 한 번뿐인데 하루 한도와 맞지 않습니다 — 2만 행짜리 표는 500행씩
|
|
245
|
+
나눠 읽어도 한 번 훑는 데 42회가 듭니다. 그래서 **워크스페이스당 한 번, 72시간**
|
|
246
|
+
동안 조회 한도를 풉니다.
|
|
247
|
+
|
|
248
|
+
워크스페이스 **설정 → 요금제**에서 켜거나, 관리자 키로 이렇게 켤 수 있습니다:
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
curl -X POST https://rootr.io/api/v1/workspaces/<워크스페이스 id>/billing/migration-grace \
|
|
252
|
+
-H "x-api-key: $ROOTR_API_KEY"
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
같은 주소에 `GET` 하면 언제 켰는지·언제 끝나는지를 돌려줍니다. 한 번 쓴 뒤에는
|
|
256
|
+
거절되고 "언제 썼는지"를 함께 알려 줍니다.
|
|
257
|
+
|
|
224
258
|
### 서명문서 · 연구노트 (sign)
|
|
225
259
|
|
|
226
260
|
서명문서는 마크다운 문서인데 **올리는 순간 본문이 얼고**, 결재라인에 적힌 사람들이
|
|
@@ -312,7 +346,7 @@ rootr memory forget <id> # 폐기(--hard면 행 삭제)
|
|
|
312
346
|
|
|
313
347
|
## MCP 서버로 사용하기
|
|
314
348
|
|
|
315
|
-
`rootr mcp`는 stdio로 MCP(Model Context Protocol) 서버를 구동합니다. 제공 도구
|
|
349
|
+
`rootr mcp`는 stdio로 MCP(Model Context Protocol) 서버를 구동합니다. 제공 도구 178종:
|
|
316
350
|
|
|
317
351
|
노드를 가리키는 인자(`target`, `databaseId`, `spreadsheetId`, `formId`, `crmId`, `trackerId`,
|
|
318
352
|
`recordingId`, `presentationId`, `whiteboardId`, `logId`, `parentId` 등)는 **노드 id와 경로를 모두**
|
|
@@ -406,6 +440,9 @@ rootr memory forget <id> # 폐기(--hard면 행 삭제)
|
|
|
406
440
|
|---|---|
|
|
407
441
|
| `rootr_read_database` | 스키마(열 정의)+행 전체 읽기 — **다른 표 도구를 쓰기 전에 먼저** (`includeBody: true` 면 행마다 상세 내용까지) |
|
|
408
442
|
| `rootr_list_rows` | 행만 조회(스키마 제외, `includeBody` 지원, `backlinks: true`면 "나를 가리키는 다른 표의 행"도 함께) |
|
|
443
|
+
| `rootr_find_similar_rows` | 같은 표에서 **뜻이 가까운 행** 찾기(행 벡터). "검색 색인에서 제외"한 칸은 색인하지 않고, "본인 행만" 표는 내 행만 돌려준다. 표 안에서 **특히 닮은 행만**(`similarityLevel` high·mid) 돌려준다 — 한 표의 무관한 행도 코사인 0.8을 넘기 때문. `state`: `indexing`(색인 중)·`sync-off`(그래프 동기화 꺼짐)·`ready` |
|
|
444
|
+
| `rootr_set_row_vectors` | **벡터 칸**(`rootr_add_column` type `vector` + `dimensions`)에 내 임베딩을 행마다 넣는다(한 번에 500개, 다시 보내면 교체). 루터는 임베딩을 만들지 않는다(AI 크레딧 0) |
|
|
445
|
+
| `rootr_query_vectors` | 벡터 칸에서 내가 준 벡터와 코사인이 가까운 행 찾기(`topK`·`minScore`). 행 권한 그대로 |
|
|
409
446
|
| `rootr_add_row` | 행 추가 (`values`는 열 이름 또는 id로 지정, `body`로 상세 내용까지) |
|
|
410
447
|
| `rootr_update_row` | 행 수정 (칸반 카드 이동 = select 열 값 변경, `body`로 상세 내용 교체) |
|
|
411
448
|
| `rootr_bulk_create_rows` | 행 여러 개를 한 번에 추가 |
|
|
@@ -429,6 +466,11 @@ rootr memory forget <id> # 폐기(--hard면 행 삭제)
|
|
|
429
466
|
| `rootr_list_database_buttons` | 표 위 **버튼** 목록 보기(고칠 수 있는지 `myLevel`도 함께) |
|
|
430
467
|
| `rootr_set_database_buttons` | 버튼 만들고 고치기 — **목록 통째로 교체**(남길 것도 같이 보내야 함) |
|
|
431
468
|
| `rootr_run_database_button` | 버튼 누르기 — 행 만들기·값 채우기·AI로 칸 채우기가 순서대로 |
|
|
469
|
+
| `rootr_list_database_automations` | 표의 **자동 규칙** 목록 보기 |
|
|
470
|
+
| `rootr_set_database_automations` | 자동 규칙 저장 — "값이 이렇게 되면 이 일을 해라"·정해진 시각(목록 통째로 교체) |
|
|
471
|
+
| `rootr_import_folded_sheets` | 시트가 수백 장인 엑셀을 **표 하나로 접어** 가져오기(먼저 `dryRun`) |
|
|
472
|
+
| `rootr_form_mapping` | 폼 질문이 표의 **어느 칸**으로 가는지 + 짝 없는 질문(값이 버려짐) |
|
|
473
|
+
| `rootr_set_form_mapping` | 질문↔칸 짝을 손으로 정하기 — 이름이 달라도 값이 안 사라지게 |
|
|
432
474
|
| `rootr_list_document_commits` | 공개 문서에 온 변경 제안 목록 |
|
|
433
475
|
| `rootr_merge_document_commit` | 변경 제안 반영(세 벌 병합 — 덮어쓰기 아님) |
|
|
434
476
|
| `rootr_reject_document_commit` | 변경 제안 거절(사유는 제안자에게 전달) |
|
|
@@ -451,6 +493,7 @@ rootr memory forget <id> # 폐기(--hard면 행 삭제)
|
|
|
451
493
|
rootr db buttons <표> # 지금 달린 버튼 보기
|
|
452
494
|
rootr db buttons <표> --file buttons.json # 목록 통째로 저장(남길 것도 같이)
|
|
453
495
|
rootr db button-run <표> <버튼id> # 한 번 누르기 (--rows id,id 로 고른 행 지정)
|
|
496
|
+
rootr db automations <표> --file rules.json # 자동 규칙 — 사람이 안 눌러도 도는 것
|
|
454
497
|
rootr db view <표> <뷰> --scale year # 달력 보기를 주·달·해 중에서
|
|
455
498
|
```
|
|
456
499
|
|
|
@@ -462,7 +505,38 @@ rootr db view <표> <뷰> --scale year # 달력 보기를 주·달·해
|
|
|
462
505
|
] }]
|
|
463
506
|
```
|
|
464
507
|
|
|
465
|
-
|
|
508
|
+
**다른 표에 행 만들기.** `add_row` 에 `database`(표 id 또는 트리 경로)와
|
|
509
|
+
`link: { "relation": "<대상 표의 관계 칸>", "from": "selected" }` 를 주면, **누른 행이 이미
|
|
510
|
+
연결된 행**이 그 표에 생깁니다. 지원자 행에서 전화 버튼을 누르면 콜 이력에 그 지원자가 붙은
|
|
511
|
+
행이 생기는 식입니다 — 이게 없으면 표를 오가며 같은 사람을 두 번 찾습니다.
|
|
512
|
+
|
|
513
|
+
```json
|
|
514
|
+
[{ "label": "부재 기록", "icon": "📞", "steps": [
|
|
515
|
+
{ "kind": "add_row", "database": "/01. 채용 파이프라인/콜 이력",
|
|
516
|
+
"values": { "결과": "부재", "통화일시": "@today", "재통화 예정일": "@today+1" },
|
|
517
|
+
"link": { "relation": "지원자", "from": "selected" } }
|
|
518
|
+
] }]
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
**사람이 기억해서 눌러야 하는 일**은 버튼이 아니라 **자동 규칙**으로 겁니다 — 버튼은 안 누른
|
|
522
|
+
날 그 일이 그냥 빠집니다. 단계 문법은 버튼과 똑같고, 조건은 거의 언제나 `changed_to` 입니다
|
|
523
|
+
(`is` 는 그 뒤로 그 행을 고칠 때마다 계속 참이라 행이 몇 벌씩 생깁니다).
|
|
524
|
+
|
|
525
|
+
```json
|
|
526
|
+
[{ "label": "투입확정 해피콜 3건", "on": ["updated"],
|
|
527
|
+
"when": { "property": "상태", "op": "changed_to", "value": "투입확정" },
|
|
528
|
+
"steps": [
|
|
529
|
+
{ "kind": "add_row", "database": "/03. 투입·운영/해피콜",
|
|
530
|
+
"values": { "차수": "1차", "예정일": "@today+7" },
|
|
531
|
+
"link": { "relation": "지원자", "from": "selected" } }
|
|
532
|
+
] },
|
|
533
|
+
{ "label": "아침 재통화 대기열", "on": ["schedule"], "schedule": { "at": "09:00" },
|
|
534
|
+
"when": { "property": "재통화 예정일", "op": "is", "value": "@today" },
|
|
535
|
+
"steps": [{ "kind": "update_rows", "target": "selected", "values": { "오늘 할 일": true } }] }]
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
스캐폴드로 표를 지을 때도 `database.buttons` · `database.automations` 에 같은 모양을 넣으면
|
|
539
|
+
**표와 함께** 달립니다.
|
|
466
540
|
|
|
467
541
|
**행에 댓글 달기.** 표의 한 행에 댓글을 달려면 `rootr_comment_document` 에 **표**를
|
|
468
542
|
`target` 으로, **행 id**를 `blockId` 으로 줍니다(읽기는 `rootr_list_document_comments`,
|
|
@@ -479,6 +553,10 @@ rootr db view <표> <뷰> --scale year # 달력 보기를 주·달·해
|
|
|
479
553
|
명령줄에서는 `rootr access <경로|id> --private`, `--grant <userId> --level READ`,
|
|
480
554
|
`--revoke <userId>` 입니다. (웹에 공개하는 것과는 다릅니다 — 그건 `rootr_set_document_public`.)
|
|
481
555
|
|
|
556
|
+
질문이 표의 어느 칸으로 가는지는 `rootr form mapping <폼>` 으로 봅니다. 질문 이름과 칸 이름이
|
|
557
|
+
같아야 값이 넘어가므로, 다르면 **아무 경고 없이 그 답이 버려집니다** — 표를 직접 만들어 연결한
|
|
558
|
+
직후에는 반드시 한 번 확인하세요. 짝을 손으로 정하려면 `--set '{"질문id":"칸id"}'` 입니다.
|
|
559
|
+
|
|
482
560
|
응답 모을 곳은 `rootr form collect <폼> --to db|sheet`로 **만들면서** 연결합니다 —
|
|
483
561
|
표로 만들면 폼 질문 그대로 칸이 생기므로, 표를 미리 만들고 칸 이름을 맞출 필요가 없습니다
|
|
484
562
|
(이름이 하나라도 어긋나면 그 칸은 영영 빈 칸으로 남습니다). 스캐폴드 트리에서는 폼 노드에
|
|
@@ -535,6 +613,29 @@ rootr db view <표> <뷰> --scale year # 달력 보기를 주·달·해
|
|
|
535
613
|
| `rootr_set_document_public` | 문서 전용 공개 설정 변경 |
|
|
536
614
|
| `rootr_document_public_status` | 문서 전용 공개 상태 |
|
|
537
615
|
|
|
616
|
+
#### 방문자 일정 등록(예약) · 구글 캘린더 (docs:read/docs:write)
|
|
617
|
+
|
|
618
|
+
공개한 **표**를 예약 페이지로 씁니다. 방문자가 빈 시간을 골라 잡으면 그 표에 행 하나로
|
|
619
|
+
들어옵니다. 남의 예약은 방문자에게 안 보이고(공개 페이로드에서 행을 뺍니다), 같은 시간을
|
|
620
|
+
동시에 눌러도 한 명만 들어갑니다. 예약은 **공개 주소 위에 서는 기능**이라 `rootr_publish_node`
|
|
621
|
+
를 먼저 해야 합니다.
|
|
622
|
+
|
|
623
|
+
| 도구 | 설명 |
|
|
624
|
+
|---|---|
|
|
625
|
+
| `rootr_get_booking` | 예약 설정·규칙·구글 연결 상태 보기 |
|
|
626
|
+
| `rootr_set_booking` | 예약 켜기/끄기와 규칙(요일·시간·길이·여유·며칠 전·하루 최대·쉬는 날·**막는 시간**·확정 방식·물어볼 칸·**결과 메일**·**구글 밋**·**방문자 직접 취소**·**방문자 직접 시간 변경**·**미리 알림**) |
|
|
627
|
+
| `rootr_booking_slots` | 방문자에게 실제로 보이는 빈 시간(규칙이 뜻대로 걸렸는지 확인) |
|
|
628
|
+
|
|
629
|
+
방문자 화면은 **방문자 자신의 시간대**로 빈 시간을 보여주고(고칠 수도 있습니다), 서버와
|
|
630
|
+
주고받는 값은 끝까지 주인 시간대입니다. 확정·이동 메일에는 **일정 초대장(.ics)** 이 붙어
|
|
631
|
+
방문자 캘린더에 바로 들어가고, 시간을 옮기면 그 일정이 고쳐지고 취소하면 사라집니다.
|
|
632
|
+
메일 속 링크 하나로 방문자가 **직접 취소하거나 시간을 옮길** 수 있고(`allowVisitorCancel`
|
|
633
|
+
/ `allowVisitorReschedule`), `reminders`(분 단위, 예 `[1440, 60]`)로 약속 전에 양쪽에 한 번
|
|
634
|
+
더 알립니다 — 기본은 하루 전 한 번입니다.
|
|
635
|
+
| `rootr_list_google_calendars` | 연결한 구글 계정과 그 캘린더 목록 |
|
|
636
|
+
| `rootr_connect_google_calendar` | 구글 동의 주소 만들기(허용은 브라우저에서 사람이 한 번) |
|
|
637
|
+
| `rootr_disconnect_google_calendar` | 구글 연결 끊기(구글 쪽 권한도 거둠) |
|
|
638
|
+
|
|
538
639
|
#### 스프레드시트 (docs:read/docs:write)
|
|
539
640
|
|
|
540
641
|
| 도구 | 설명 |
|
|
@@ -705,7 +806,10 @@ curl "$BASE/pages/$ID/live-data" -H "x-api-key: $KEY"
|
|
|
705
806
|
```
|
|
706
807
|
|
|
707
808
|
`liveStats`/`liveTable`/`liveChart`의 `source.nodeId`는 같은 워크스페이스의
|
|
708
|
-
DATABASE·LOG 노드이고, 칸은 **이름**으로 가리킵니다(칸 id가 아닙니다).
|
|
809
|
+
DATABASE·SPREADSHEET·LOG 노드이고, 칸은 **이름**으로 가리킵니다(칸 id가 아닙니다).
|
|
810
|
+
`liveChart`는 **차트 46종**(지난 기간 대비 증감이 붙는 KPI, 막대+선 이중축, 히트맵, 생키, 간트, 피벗…)을 그리고,
|
|
811
|
+
어느 블록이든 `width: half | third | twoThirds` 로 나란히 놓아 **실시간 대시보드**를 만들 수 있습니다 —
|
|
812
|
+
`/llms.txt`의 "Dashboards & charts" 참고.
|
|
709
813
|
`form` 블록의 `formNodeId`에 폼 노드를 걸면 방문자가 **그 자리에서 신청**합니다 —
|
|
710
814
|
폼을 따로 공개할 필요가 없습니다. 비공개(PRIVATE) 서브트리에 있는 표·폼은 공개
|
|
711
815
|
페이지에서 조용히 빠집니다(일부러 그렇습니다).
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ citations back to the exact paragraph.
|
|
|
11
11
|
*(한국어 문서: [README.ko.md](https://github.com/gwmage/rootr-cli/blob/main/README.ko.md))*
|
|
12
12
|
|
|
13
13
|
- `rootr` CLI — documents, databases, forms, signed documents, publishing, permissions, memory
|
|
14
|
-
- `rootr mcp` — stdio MCP server, **
|
|
14
|
+
- `rootr mcp` — stdio MCP server, **178 tools** (see [MCP tools](#mcp-tools))
|
|
15
15
|
|
|
16
16
|
Plain Node.js ESM, no build step. Node 18+ (uses the built-in `fetch`).
|
|
17
17
|
|
|
@@ -149,6 +149,10 @@ rootr append /notes/log.md "deploy finished"
|
|
|
149
149
|
rootr append /notes/log.md "- one more item" --heading "## Todo"
|
|
150
150
|
cat diff.md | rootr append /notes/log.md
|
|
151
151
|
|
|
152
|
+
# Embed a LIVE table (or sheet / deck / board) inside a document — like Notion's linked database
|
|
153
|
+
rootr embed /meetings/weekly.md /projects/tasks
|
|
154
|
+
rootr embed /meetings/weekly.md /projects/tasks --heading "## Tasks"
|
|
155
|
+
|
|
152
156
|
rootr edit /notes/todo.md --find "- [ ] deploy" --replace "- [x] deploy"
|
|
153
157
|
rootr edit /notes/todo.md --find "TODO" --replace "DONE" --all
|
|
154
158
|
|
|
@@ -193,9 +197,26 @@ rootr db lock /projects/tasks --schema managers --rows own --locked "Approved,Sc
|
|
|
193
197
|
rootr db notify /projects/tasks --file rules.json # notification rules
|
|
194
198
|
rootr db buttons /projects/tasks --file buttons.json # buttons that do work when pressed
|
|
195
199
|
rootr db button-run /projects/tasks fill-summary --rows r1,r2
|
|
200
|
+
rootr db automations /projects/tasks --file rules.json # "when a value becomes X, do Y" (also: at a set time)
|
|
201
|
+
rootr db rows-new /projects/tasks --file rows.json --upsert-key 외부키 # idempotent load: retries cannot duplicate
|
|
202
|
+
rootr db import-sheets sites.xlsx --ws <id> --dry # fold a one-sheet-per-record workbook into ONE table
|
|
196
203
|
rootr db row-page <rowId> --type RECORDING # give one row a typed detail page
|
|
197
204
|
```
|
|
198
205
|
|
|
206
|
+
`db automations` takes the same step syntax as `db buttons`, so there is nothing new to
|
|
207
|
+
learn — the difference is that nobody has to press it. A rule is
|
|
208
|
+
`{ label, on: ["updated"], when: { property, op: "changed_to", value }, steps: [...] }`;
|
|
209
|
+
add `on: ["schedule"]` with `schedule: { at: "09:00" }` for a daily job (Korean time).
|
|
210
|
+
Prefer `changed_to` over `is`: `is` stays true on every later edit, so a rule that creates
|
|
211
|
+
rows would create them again each time the row is saved.
|
|
212
|
+
|
|
213
|
+
`--upsert-key` is what makes a migration or a sync safe to retry — without it, retrying
|
|
214
|
+
after a partial failure silently double-loads (a real incident: 903 duplicate rows).
|
|
215
|
+
|
|
216
|
+
`db import-sheets` always deserves a `--dry` first: it prints the shape it read, the
|
|
217
|
+
columns it will make and the first rows, and creates nothing. Folding hundreds of sheets
|
|
218
|
+
the wrong way costs far more to undo than to check.
|
|
219
|
+
|
|
199
220
|
### Forms
|
|
200
221
|
|
|
201
222
|
```bash
|
|
@@ -204,10 +225,17 @@ rootr form new /intake/request --collect db \
|
|
|
204
225
|
rootr form show /intake/request # read the questions before changing them
|
|
205
226
|
rootr form set /intake/request --fields '[...]' # replaces the question set
|
|
206
227
|
rootr form collect /intake/request --to sheet # create and wire a destination
|
|
228
|
+
rootr form mapping /intake/request # which column each question feeds
|
|
229
|
+
rootr form mapping /intake/request --set '{"f_name":"p_title"}'
|
|
207
230
|
rootr form responses /intake/request --latest # --latest = newest one per person
|
|
208
231
|
rootr form response-edit <responseId> --values '{"Email":"a@b.com"}'
|
|
209
232
|
```
|
|
210
233
|
|
|
234
|
+
Run `form mapping` right after pointing a form at a hand-built table. Answers reach the
|
|
235
|
+
table by matching the question name to the column name, so a question the table has no
|
|
236
|
+
column for is **dropped with no error anywhere** — this command is the only place that
|
|
237
|
+
says so, and `--set` pins the pairs by hand when the wording differs ("성함" vs "이름").
|
|
238
|
+
|
|
211
239
|
`--fields` takes a JSON array as a **string**, not a file path.
|
|
212
240
|
|
|
213
241
|
18 question types, including `text`, `email`, `phone`, `url`, `rating`, `scale`, `time`, `file`,
|
|
@@ -329,6 +357,8 @@ pollute the queue.
|
|
|
329
357
|
|
|
330
358
|
Only **read-type** calls (`docs:read` / `graph:read` / `ask`) made programmatically (API key or
|
|
331
359
|
MCP) are metered. Writes and uploads are not limited.
|
|
360
|
+
Reading a published public URL with `rootr_read` (`rootr.io/p/{slug}`, including another workspace's document) counts as one
|
|
361
|
+
read as well; opening the same URL in a browser does not.
|
|
332
362
|
|
|
333
363
|
| Plan | Limit |
|
|
334
364
|
| --- | --- |
|
|
@@ -341,9 +371,25 @@ At 80% of the limit, MCP tool responses append a note with the remaining count.
|
|
|
341
371
|
get a 429 with an upgrade link. The response headers carry the same information
|
|
342
372
|
(`X-RateLimit-Remaining`, `X-RateLimit-Reset`, `X-RateLimit-Window`).
|
|
343
373
|
|
|
374
|
+
#### First migration: a 72-hour grace period
|
|
375
|
+
|
|
376
|
+
Moving your data in happens once, but it does not fit a daily cap — a 20,000-row
|
|
377
|
+
table costs 42 calls to read through even in 500-row pages. So each workspace can
|
|
378
|
+
lift the read limit **once, for 72 hours**.
|
|
379
|
+
|
|
380
|
+
Turn it on in **Settings → Plan**, or with an admin key:
|
|
381
|
+
|
|
382
|
+
```bash
|
|
383
|
+
curl -X POST https://rootr.io/api/v1/workspaces/<workspace id>/billing/migration-grace \
|
|
384
|
+
-H "x-api-key: $ROOTR_API_KEY"
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
`GET` on the same path tells you when it started and when it ends. A second request
|
|
388
|
+
is refused and says when the grace was used.
|
|
389
|
+
|
|
344
390
|
## MCP tools
|
|
345
391
|
|
|
346
|
-
`rootr mcp` speaks MCP over stdio.
|
|
392
|
+
`rootr mcp` speaks MCP over stdio. 178 tools:
|
|
347
393
|
|
|
348
394
|
| Group | Count | Tools |
|
|
349
395
|
|---|---|---|
|
|
@@ -365,9 +411,27 @@ get a 429 with an upgrade link. The response headers carry the same information
|
|
|
365
411
|
| Attachments | 2 | upload a file, attach an image straight into a document |
|
|
366
412
|
| Agent memory | 3 | remember, recall, forget |
|
|
367
413
|
| Webhooks | 3 | list, create (secret shown once), delete |
|
|
414
|
+
| Visitor booking & Google Calendar | 6 | turn a published table into a booking page, rules, open slots, connect / list / disconnect Google Calendar |
|
|
368
415
|
| Root-cause Q&A | 1 | ask the workspace knowledge graph, answer with citations |
|
|
369
416
|
| Feedback | 1 | send feedback to the Rootr team |
|
|
370
417
|
|
|
418
|
+
Open hours can be narrowed by blocked times — one afternoon, lunch every day, Monday mornings, or a whole
|
|
419
|
+
weekday — with `blockedTimes` on `rootr_set_booking` (CLI: `--block-time "daily 12:00-13:00, mon 09:00-11:00, fri"`).
|
|
420
|
+
|
|
421
|
+
Every booking is emailed to both sides (`notifyVisitor` / `notifyEmails`), and `google.meet` adds a Google Meet
|
|
422
|
+
room per booking — the link lands in a "회의 링크" column and in both emails (CLI: `--meet on --notify-email me@acme.com`).
|
|
423
|
+
Visitors cancel themselves from a link in their email (`allowVisitorCancel`, CLI `--self-cancel on|off`) — the link is a
|
|
424
|
+
secret only that booking's email carries, so no account is needed. The same link also **moves** the booking to
|
|
425
|
+
another time (`allowVisitorReschedule`, CLI `--self-move on|off`), picked under one lock so the new slot cannot be
|
|
426
|
+
taken in between. Slots are shown in the **visitor's own time zone** (they can switch it), every confirmation carries
|
|
427
|
+
a **calendar invite (.ics)** that updates itself when the time moves and cancels itself when the booking is cancelled,
|
|
428
|
+
and `reminders` emails both sides before the meeting (CLI `--remind 1d,1h`, default a day before, `--remind off` to stop).
|
|
429
|
+
|
|
430
|
+
Visitor booking turns a published DATABASE into a scheduling page: visitors pick an open slot and each
|
|
431
|
+
booking lands as one row. Other people's bookings are never exposed publicly, double-booking is blocked
|
|
432
|
+
server-side, and Google Calendar is optional — busy times block slots and confirmed bookings are written
|
|
433
|
+
back. Connecting a Google account needs a person to approve once in a browser; everything else is a tool.
|
|
434
|
+
|
|
371
435
|
Guidance baked into the tool descriptions: agents should reach for `rootr_append` and
|
|
372
436
|
`rootr_edit`, and use `rootr_write` only for a genuine full rewrite (ideally with `ifMatch`).
|
|
373
437
|
Tools that take a `workspace` argument fall back to `ROOTR_WORKSPACE` / the config file, and
|
|
@@ -405,14 +469,32 @@ curl -X PATCH "$BASE/pages/$ID" -d '{"config":{"theme":"warm"}}' ...
|
|
|
405
469
|
curl "$BASE/pages/$ID/live-data" -H "x-api-key: $KEY"
|
|
406
470
|
```
|
|
407
471
|
|
|
408
|
-
For `liveStats` / `liveTable` / `liveChart`, `source.nodeId` is a DATABASE or LOG node in the
|
|
409
|
-
same workspace and columns are referenced **by name** (not by column id).
|
|
472
|
+
For `liveStats` / `liveTable` / `liveChart`, `source.nodeId` is a DATABASE, SPREADSHEET or LOG node in the
|
|
473
|
+
same workspace and columns are referenced **by name** (not by column id). `liveChart` draws **46 chart
|
|
474
|
+
kinds** (KPI with period-over-period change, combo/dual axis, heatmap, sankey, gantt, pivot…) and any block
|
|
475
|
+
takes `width: half | third | twoThirds` so a page becomes a **live dashboard** — see "Dashboards & charts" in `/llms.txt`. Point a `form` block's
|
|
410
476
|
`formNodeId` at a form node and visitors submit **right there** — the form does not have to be
|
|
411
477
|
published separately. Tables and forms that live under a PRIVATE subtree are silently dropped
|
|
412
478
|
from a public page, on purpose.
|
|
413
479
|
|
|
414
480
|
Publishing works like any other node: `POST /v1/nodes/:id/publish` → `rootr.io/p/{slug}`.
|
|
415
481
|
|
|
482
|
+
### Embedding a table inside a document
|
|
483
|
+
|
|
484
|
+
A document can show another node — a table, spreadsheet, presentation, whiteboard, form,
|
|
485
|
+
recording, log store or issue tracker — **live**, the same as the editor's "Embed" block
|
|
486
|
+
(Notion's linked database). Edits to the table appear in the document; it is not a copy.
|
|
487
|
+
|
|
488
|
+
- MCP: `rootr_embed_node` (`target` = the document, `node` = what to embed; both take a path or
|
|
489
|
+
an id; optional `underHeading`).
|
|
490
|
+
- CLI: `rootr embed <doc> <node> [--heading "## X"]`.
|
|
491
|
+
- REST: `POST /v1/documents/:id/embeds` with `{ "node": "/projects/tasks" }`.
|
|
492
|
+
- Or write a line containing only `[[embed:/projects/tasks]]` (or `[[embed:<node id>]]`) in any
|
|
493
|
+
`rootr_write` / `rootr_append` content. Paths are turned into ids when saved; an unknown path —
|
|
494
|
+
or one you cannot read — is rejected with 400 and nothing is written.
|
|
495
|
+
- Scaffolding: inside a tree, a document's `content` can embed a node built in the same tree by
|
|
496
|
+
its name, e.g. `[[embed:Tasks]]`.
|
|
497
|
+
|
|
416
498
|
### Presentations
|
|
417
499
|
|
|
418
500
|
Decks are authored with `rootr_create_presentation`, `rootr_read_presentation`,
|