studiograph 1.1.3 → 1.2.0-beta.10
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.md +2 -8
- package/dist/agent/orchestrator.d.ts +53 -0
- package/dist/agent/orchestrator.js +197 -12
- package/dist/agent/orchestrator.js.map +1 -1
- package/dist/agent/prompts/system.md +43 -11
- package/dist/agent/skill-loader.d.ts +48 -0
- package/dist/agent/skill-loader.js +166 -0
- package/dist/agent/skill-loader.js.map +1 -0
- package/dist/agent/skills/{bundled/enrich-entities.md → enrich-entities.md} +12 -0
- package/dist/agent/skills/entity-schema.md +502 -0
- package/dist/agent/skills/obsidian-source-setup.md +246 -0
- package/dist/agent/skills/sync-configuration.md +144 -0
- package/dist/agent/skills/sync-setup.md +84 -0
- package/dist/agent/tools/connector-tools.d.ts +37 -0
- package/dist/agent/tools/connector-tools.js +132 -0
- package/dist/agent/tools/connector-tools.js.map +1 -0
- package/dist/agent/tools/fs-tools.d.ts +39 -0
- package/dist/agent/tools/fs-tools.js +106 -0
- package/dist/agent/tools/fs-tools.js.map +1 -0
- package/dist/agent/tools/graph-tools.d.ts +33 -1
- package/dist/agent/tools/graph-tools.js +192 -44
- package/dist/agent/tools/graph-tools.js.map +1 -1
- package/dist/agent/tools/load-skill.d.ts +1 -1
- package/dist/agent/tools/load-skill.js +1 -1
- package/dist/agent/tools/load-skill.js.map +1 -1
- package/dist/agent/tools/ops-tools.d.ts +24 -0
- package/dist/agent/tools/ops-tools.js +542 -0
- package/dist/agent/tools/ops-tools.js.map +1 -0
- package/dist/agent/tools/sync-tools.d.ts +33 -0
- package/dist/agent/tools/sync-tools.js +947 -0
- package/dist/agent/tools/sync-tools.js.map +1 -0
- package/dist/auth/github.d.ts +11 -8
- package/dist/auth/github.js +56 -75
- package/dist/auth/github.js.map +1 -1
- package/dist/cli/colors.d.ts +54 -0
- package/dist/cli/colors.js +133 -0
- package/dist/cli/colors.js.map +1 -0
- package/dist/cli/commands/app.js +121 -18
- package/dist/cli/commands/app.js.map +1 -1
- package/dist/cli/commands/auth.d.ts +1 -1
- package/dist/cli/commands/auth.js +26 -10
- package/dist/cli/commands/auth.js.map +1 -1
- package/dist/cli/commands/clone.d.ts +9 -0
- package/dist/cli/commands/clone.js +167 -0
- package/dist/cli/commands/clone.js.map +1 -0
- package/dist/cli/commands/commit.d.ts +8 -0
- package/dist/cli/commands/commit.js +44 -0
- package/dist/cli/commands/commit.js.map +1 -0
- package/dist/cli/commands/connector.js +10 -2
- package/dist/cli/commands/connector.js.map +1 -1
- package/dist/cli/commands/deploy.d.ts +4 -6
- package/dist/cli/commands/deploy.js +292 -115
- package/dist/cli/commands/deploy.js.map +1 -1
- package/dist/cli/commands/enrich.d.ts +11 -0
- package/dist/cli/commands/enrich.js +135 -0
- package/dist/cli/commands/enrich.js.map +1 -0
- package/dist/cli/commands/graphrag.d.ts +12 -0
- package/dist/cli/commands/graphrag.js +122 -0
- package/dist/cli/commands/graphrag.js.map +1 -0
- package/dist/cli/commands/init.js +29 -196
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/join.js +23 -3
- package/dist/cli/commands/join.js.map +1 -1
- package/dist/cli/commands/orphans.d.ts +8 -0
- package/dist/cli/commands/orphans.js +125 -0
- package/dist/cli/commands/orphans.js.map +1 -0
- package/dist/cli/commands/provision.js +11 -7
- package/dist/cli/commands/provision.js.map +1 -1
- package/dist/cli/commands/r2.js +8 -2
- package/dist/cli/commands/r2.js.map +1 -1
- package/dist/cli/commands/redeploy.d.ts +9 -0
- package/dist/cli/commands/redeploy.js +203 -0
- package/dist/cli/commands/redeploy.js.map +1 -0
- package/dist/cli/commands/reset.d.ts +12 -0
- package/dist/cli/commands/reset.js +137 -0
- package/dist/cli/commands/reset.js.map +1 -0
- package/dist/cli/commands/resolve.d.ts +8 -0
- package/dist/cli/commands/resolve.js +85 -0
- package/dist/cli/commands/resolve.js.map +1 -0
- package/dist/cli/commands/review.d.ts +19 -0
- package/dist/cli/commands/review.js +128 -0
- package/dist/cli/commands/review.js.map +1 -0
- package/dist/cli/commands/serve.js +55 -8
- package/dist/cli/commands/serve.js.map +1 -1
- package/dist/cli/commands/source.d.ts +16 -0
- package/dist/cli/commands/source.js +159 -0
- package/dist/cli/commands/source.js.map +1 -0
- package/dist/cli/commands/start.js +307 -55
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/sync-entities.d.ts +13 -0
- package/dist/cli/commands/sync-entities.js +242 -0
- package/dist/cli/commands/sync-entities.js.map +1 -0
- package/dist/cli/commands/sync.js +81 -5
- package/dist/cli/commands/sync.js.map +1 -1
- package/dist/cli/index.js +45 -9
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/scaffolding.d.ts +2 -1
- package/dist/cli/scaffolding.js +38 -23
- package/dist/cli/scaffolding.js.map +1 -1
- package/dist/cli/setup-wizard.d.ts +30 -0
- package/dist/cli/setup-wizard.js +244 -0
- package/dist/cli/setup-wizard.js.map +1 -0
- package/dist/cli/sync-review-interactive.d.ts +31 -0
- package/dist/cli/sync-review-interactive.js +393 -0
- package/dist/cli/sync-review-interactive.js.map +1 -0
- package/dist/cli/theme.d.ts +31 -0
- package/dist/cli/theme.js +116 -0
- package/dist/cli/theme.js.map +1 -0
- package/dist/core/graph.d.ts +40 -12
- package/dist/core/graph.js +344 -104
- package/dist/core/graph.js.map +1 -1
- package/dist/core/migration-runner.d.ts +4 -1
- package/dist/core/migration-runner.js +14 -3
- package/dist/core/migration-runner.js.map +1 -1
- package/dist/core/types.d.ts +2 -4
- package/dist/core/types.js +1 -2
- package/dist/core/types.js.map +1 -1
- package/dist/core/user-config.d.ts +12 -0
- package/dist/core/user-config.js.map +1 -1
- package/dist/core/workspace-manager.d.ts +6 -1
- package/dist/core/workspace-manager.js +29 -4
- package/dist/core/workspace-manager.js.map +1 -1
- package/dist/core/workspace.d.ts +13 -5
- package/dist/core/workspace.js +115 -33
- package/dist/core/workspace.js.map +1 -1
- package/dist/lib/lib/utils.d.ts +2 -0
- package/dist/lib/lib/utils.js +6 -0
- package/dist/lib/lib/utils.js.map +1 -0
- package/dist/mcp/connector-manager.d.ts +7 -3
- package/dist/mcp/connector-manager.js +61 -16
- package/dist/mcp/connector-manager.js.map +1 -1
- package/dist/mcp/connectors/asana.d.ts +2 -0
- package/dist/mcp/connectors/asana.js +20 -0
- package/dist/mcp/connectors/asana.js.map +1 -0
- package/dist/mcp/connectors/definitions.d.ts +3 -1
- package/dist/mcp/connectors/definitions.js +19 -127
- package/dist/mcp/connectors/definitions.js.map +1 -1
- package/dist/mcp/connectors/figma.d.ts +5 -0
- package/dist/mcp/connectors/figma.js +21 -0
- package/dist/mcp/connectors/figma.js.map +1 -0
- package/dist/mcp/connectors/gdrive.d.ts +2 -0
- package/dist/mcp/connectors/gdrive.js +20 -0
- package/dist/mcp/connectors/gdrive.js.map +1 -0
- package/dist/mcp/connectors/granola.d.ts +2 -0
- package/dist/mcp/connectors/granola.js +12 -0
- package/dist/mcp/connectors/granola.js.map +1 -0
- package/dist/mcp/connectors/linear.d.ts +2 -0
- package/dist/mcp/connectors/linear.js +19 -0
- package/dist/mcp/connectors/linear.js.map +1 -0
- package/dist/mcp/connectors/obsidian.d.ts +2 -0
- package/dist/mcp/connectors/obsidian.js +19 -0
- package/dist/mcp/connectors/obsidian.js.map +1 -0
- package/dist/mcp/connectors/pipedrive.d.ts +2 -0
- package/dist/mcp/connectors/pipedrive.js +20 -0
- package/dist/mcp/connectors/pipedrive.js.map +1 -0
- package/dist/mcp/connectors/slack.d.ts +2 -0
- package/dist/mcp/connectors/slack.js +21 -0
- package/dist/mcp/connectors/slack.js.map +1 -0
- package/dist/mcp/oauth-provider.d.ts +41 -0
- package/dist/mcp/oauth-provider.js +160 -0
- package/dist/mcp/oauth-provider.js.map +1 -0
- package/dist/server/index.js +97 -11
- package/dist/server/index.js.map +1 -1
- package/dist/server/plugin-loader.d.ts +8 -0
- package/dist/server/plugin-loader.js +54 -2
- package/dist/server/plugin-loader.js.map +1 -1
- package/dist/server/routes/chat.d.ts +3 -2
- package/dist/server/routes/chat.js +67 -16
- package/dist/server/routes/chat.js.map +1 -1
- package/dist/server/routes/git-api.d.ts +9 -0
- package/dist/server/routes/git-api.js +82 -0
- package/dist/server/routes/git-api.js.map +1 -0
- package/dist/server/routes/graph-api.d.ts +2 -2
- package/dist/server/routes/graph-api.js +164 -3
- package/dist/server/routes/graph-api.js.map +1 -1
- package/dist/server/routes/workspace-api.d.ts +9 -0
- package/dist/server/routes/workspace-api.js +170 -0
- package/dist/server/routes/workspace-api.js.map +1 -0
- package/dist/services/assets/base.d.ts +2 -2
- package/dist/services/assets/base.js +4 -4
- package/dist/services/assets/base.js.map +1 -1
- package/dist/services/assets/index.d.ts +6 -6
- package/dist/services/assets/index.js +12 -12
- package/dist/services/assets/index.js.map +1 -1
- package/dist/services/git.d.ts +31 -0
- package/dist/services/git.js +92 -3
- package/dist/services/git.js.map +1 -1
- package/dist/services/github-provisioner.d.ts +8 -3
- package/dist/services/github-provisioner.js +35 -8
- package/dist/services/github-provisioner.js.map +1 -1
- package/dist/services/lint-service.js +8 -1
- package/dist/services/lint-service.js.map +1 -1
- package/dist/services/markdown.js +3 -3
- package/dist/services/markdown.js.map +1 -1
- package/dist/services/memory-service.d.ts +1 -1
- package/dist/services/memory-service.js +2 -3
- package/dist/services/memory-service.js.map +1 -1
- package/dist/services/orphan-service.d.ts +31 -0
- package/dist/services/orphan-service.js +100 -0
- package/dist/services/orphan-service.js.map +1 -0
- package/dist/services/sync/commit.d.ts +60 -0
- package/dist/services/sync/commit.js +370 -0
- package/dist/services/sync/commit.js.map +1 -0
- package/dist/services/sync/context-index.d.ts +69 -0
- package/dist/services/sync/context-index.js +280 -0
- package/dist/services/sync/context-index.js.map +1 -0
- package/dist/services/sync/derive.d.ts +34 -0
- package/dist/services/sync/derive.js +164 -0
- package/dist/services/sync/derive.js.map +1 -0
- package/dist/services/sync/enrichment-state.d.ts +31 -0
- package/dist/services/sync/enrichment-state.js +63 -0
- package/dist/services/sync/enrichment-state.js.map +1 -0
- package/dist/services/sync/enrichment.d.ts +25 -0
- package/dist/services/sync/enrichment.js +121 -0
- package/dist/services/sync/enrichment.js.map +1 -0
- package/dist/services/sync/frontmatter-extractor.d.ts +40 -0
- package/dist/services/sync/frontmatter-extractor.js +273 -0
- package/dist/services/sync/frontmatter-extractor.js.map +1 -0
- package/dist/services/sync/graph-match-state.d.ts +33 -0
- package/dist/services/sync/graph-match-state.js +61 -0
- package/dist/services/sync/graph-match-state.js.map +1 -0
- package/dist/services/sync/graph-match.d.ts +53 -0
- package/dist/services/sync/graph-match.js +316 -0
- package/dist/services/sync/graph-match.js.map +1 -0
- package/dist/services/sync/graphrag-client.d.ts +43 -0
- package/dist/services/sync/graphrag-client.js +94 -0
- package/dist/services/sync/graphrag-client.js.map +1 -0
- package/dist/services/sync/graphrag-config.d.ts +16 -0
- package/dist/services/sync/graphrag-config.js +39 -0
- package/dist/services/sync/graphrag-config.js.map +1 -0
- package/dist/services/sync/graphrag-context.d.ts +14 -0
- package/dist/services/sync/graphrag-context.js +109 -0
- package/dist/services/sync/graphrag-context.js.map +1 -0
- package/dist/services/sync/graphrag-indexer.d.ts +30 -0
- package/dist/services/sync/graphrag-indexer.js +358 -0
- package/dist/services/sync/graphrag-indexer.js.map +1 -0
- package/dist/services/sync/llm.d.ts +32 -0
- package/dist/services/sync/llm.js +115 -0
- package/dist/services/sync/llm.js.map +1 -0
- package/dist/services/sync/mcp-client.d.ts +59 -0
- package/dist/services/sync/mcp-client.js +285 -0
- package/dist/services/sync/mcp-client.js.map +1 -0
- package/dist/services/sync/model-factory.d.ts +10 -0
- package/dist/services/sync/model-factory.js +24 -0
- package/dist/services/sync/model-factory.js.map +1 -0
- package/dist/services/sync/name-quality.d.ts +31 -0
- package/dist/services/sync/name-quality.js +60 -0
- package/dist/services/sync/name-quality.js.map +1 -0
- package/dist/services/sync/output-schemas.d.ts +92 -0
- package/dist/services/sync/output-schemas.js +43 -0
- package/dist/services/sync/output-schemas.js.map +1 -0
- package/dist/services/sync/prompts.d.ts +19 -0
- package/dist/services/sync/prompts.js +128 -0
- package/dist/services/sync/prompts.js.map +1 -0
- package/dist/services/sync/reconciler.d.ts +48 -0
- package/dist/services/sync/reconciler.js +295 -0
- package/dist/services/sync/reconciler.js.map +1 -0
- package/dist/services/sync/source-config.d.ts +45 -0
- package/dist/services/sync/source-config.js +208 -0
- package/dist/services/sync/source-config.js.map +1 -0
- package/dist/services/sync/source-definitions/asana.d.ts +15 -0
- package/dist/services/sync/source-definitions/asana.js +48 -0
- package/dist/services/sync/source-definitions/asana.js.map +1 -0
- package/dist/services/sync/source-definitions/definitions.d.ts +21 -0
- package/dist/services/sync/source-definitions/definitions.js +26 -0
- package/dist/services/sync/source-definitions/definitions.js.map +1 -0
- package/dist/services/sync/source-definitions/gdrive.d.ts +16 -0
- package/dist/services/sync/source-definitions/gdrive.js +68 -0
- package/dist/services/sync/source-definitions/gdrive.js.map +1 -0
- package/dist/services/sync/source-definitions/granola.d.ts +2 -0
- package/dist/services/sync/source-definitions/granola.js +28 -0
- package/dist/services/sync/source-definitions/granola.js.map +1 -0
- package/dist/services/sync/source-definitions/linear.d.ts +2 -0
- package/dist/services/sync/source-definitions/linear.js +60 -0
- package/dist/services/sync/source-definitions/linear.js.map +1 -0
- package/dist/services/sync/source-definitions/obsidian.d.ts +2 -0
- package/dist/services/sync/source-definitions/obsidian.js +55 -0
- package/dist/services/sync/source-definitions/obsidian.js.map +1 -0
- package/dist/services/sync/source-definitions/pipedrive.d.ts +2 -0
- package/dist/services/sync/source-definitions/pipedrive.js +52 -0
- package/dist/services/sync/source-definitions/pipedrive.js.map +1 -0
- package/dist/services/sync/staging.d.ts +53 -0
- package/dist/services/sync/staging.js +131 -0
- package/dist/services/sync/staging.js.map +1 -0
- package/dist/services/sync/structured-extractor.d.ts +49 -0
- package/dist/services/sync/structured-extractor.js +344 -0
- package/dist/services/sync/structured-extractor.js.map +1 -0
- package/dist/services/sync/sync-runner.d.ts +32 -0
- package/dist/services/sync/sync-runner.js +195 -0
- package/dist/services/sync/sync-runner.js.map +1 -0
- package/dist/services/sync/sync-state.d.ts +43 -0
- package/dist/services/sync/sync-state.js +154 -0
- package/dist/services/sync/sync-state.js.map +1 -0
- package/dist/services/sync/types.d.ts +203 -0
- package/dist/services/sync/types.js +8 -0
- package/dist/services/sync/types.js.map +1 -0
- package/dist/services/sync/unstructured-extractor.d.ts +29 -0
- package/dist/services/sync/unstructured-extractor.js +197 -0
- package/dist/services/sync/unstructured-extractor.js.map +1 -0
- package/dist/services/vector-service.d.ts +11 -0
- package/dist/services/vector-service.js +42 -0
- package/dist/services/vector-service.js.map +1 -1
- package/dist/utils/git.d.ts +31 -4
- package/dist/utils/git.js +65 -7
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/merge-resolver.d.ts +60 -0
- package/dist/utils/merge-resolver.js +304 -0
- package/dist/utils/merge-resolver.js.map +1 -0
- package/dist/utils/preflight.d.ts +2 -1
- package/dist/utils/preflight.js +8 -1
- package/dist/utils/preflight.js.map +1 -1
- package/dist/utils/workspace-config.d.ts +8 -0
- package/dist/utils/workspace-config.js +22 -0
- package/dist/utils/workspace-config.js.map +1 -0
- package/dist/web/_app/env.js +1 -0
- package/dist/web/_app/immutable/assets/0.BwJV4fvl.css +1 -0
- package/dist/web/_app/immutable/assets/2.DRHi7ABa.css +1 -0
- package/dist/web/_app/immutable/assets/3.CnAQdPKU.css +1 -0
- package/dist/web/_app/immutable/assets/4.BG92MufE.css +1 -0
- package/dist/web/_app/immutable/assets/5.CfrQIPYs.css +1 -0
- package/dist/web/_app/immutable/assets/ChatPanel.BNzaCFTL.css +1 -0
- package/dist/web/_app/immutable/assets/editor.D6Rjo7RE.css +1 -0
- package/dist/web/_app/immutable/chunks/4QY4j-jX.js +1 -0
- package/dist/web/_app/immutable/chunks/B4G4uWkV.js +1 -0
- package/dist/web/_app/immutable/chunks/BB_5th5W.js +3383 -0
- package/dist/web/_app/immutable/chunks/CUzqHQY_.js +1 -0
- package/dist/web/_app/immutable/chunks/CYrVHOHA.js +1 -0
- package/dist/web/_app/immutable/chunks/CksE5s8n.js +1 -0
- package/dist/web/_app/immutable/chunks/CqkleIqs.js +1 -0
- package/dist/web/_app/immutable/chunks/D0JBkEPE.js +86 -0
- package/dist/web/_app/immutable/chunks/D2K5GzLj.js +1 -0
- package/dist/web/_app/immutable/chunks/DEkoussQ.js +2 -0
- package/dist/web/_app/immutable/chunks/DW-KmHRi.js +1 -0
- package/dist/web/_app/immutable/chunks/DcCr4z9k.js +1 -0
- package/dist/web/_app/immutable/chunks/Dg2wWwJu.js +2 -0
- package/dist/web/_app/immutable/chunks/Dh_H7Owr.js +18 -0
- package/dist/web/_app/immutable/chunks/DnlgZ_Tk.js +5 -0
- package/dist/web/_app/immutable/chunks/DtVH--hH.js +6 -0
- package/dist/web/_app/immutable/chunks/PPVm8Dsz.js +1 -0
- package/dist/web/_app/immutable/chunks/SBEriEQR.js +1 -0
- package/dist/web/_app/immutable/chunks/WSUKABI_.js +1 -0
- package/dist/web/_app/immutable/chunks/YTERt3Ul.js +6 -0
- package/dist/web/_app/immutable/chunks/m_R7HatS.js +1 -0
- package/dist/web/_app/immutable/chunks/vlmEnjfO.js +1 -0
- package/dist/web/_app/immutable/entry/app.B9pwpU_x.js +2 -0
- package/dist/web/_app/immutable/entry/start.CDuNCEco.js +1 -0
- package/dist/web/_app/immutable/nodes/0.YEQhw1us.js +1 -0
- package/dist/web/_app/immutable/nodes/1.CvmHhpRy.js +1 -0
- package/dist/web/_app/immutable/nodes/2.c5k1r7dq.js +1 -0
- package/dist/web/_app/immutable/nodes/3.B24tcdLK.js +1 -0
- package/dist/web/_app/immutable/nodes/4.kX2m5Pp9.js +16 -0
- package/dist/web/_app/immutable/nodes/5.DELt6wTD.js +2 -0
- package/dist/web/_app/version.json +1 -0
- package/dist/web/index.html +41 -0
- package/package.json +21 -7
- /package/dist/agent/skills/{bundled/gather-context.md → gather-context.md} +0 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: obsidian-source-setup
|
|
3
|
+
description: Scaffold an Obsidian vault into a sync source config — explore vault structure, map directories to entity types, build field maps from frontmatter
|
|
4
|
+
loading: on-demand
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Obsidian Source Setup
|
|
8
|
+
|
|
9
|
+
Guide for mapping any Obsidian vault to a Studiograph sync source config. Every vault is different — follow these steps to explore the vault and build a config tailored to its structure.
|
|
10
|
+
|
|
11
|
+
## Step 1: Explore the Vault
|
|
12
|
+
|
|
13
|
+
Before writing any config, understand the vault's organization.
|
|
14
|
+
|
|
15
|
+
1. **List top-level directories** — use the Obsidian MCP connector or read the filesystem directly:
|
|
16
|
+
- Note every top-level folder name
|
|
17
|
+
- Identify which are content folders vs system folders (`.obsidian/`, `.smart-env/`, `Attachments/`, `Templates/`)
|
|
18
|
+
- Check for subdirectory structure (e.g., `Organizations/Clients/`, `Organizations/Vendors/`)
|
|
19
|
+
|
|
20
|
+
2. **Count files per directory** — understand the scale:
|
|
21
|
+
- Large directories (100+) are likely core entity types
|
|
22
|
+
- Small directories (<10) may not be worth a dedicated mapping
|
|
23
|
+
|
|
24
|
+
3. **Check for nested content** — some vaults use flat files, others use subfolders:
|
|
25
|
+
- `People/John Smith.md` (flat) — each file is one entity
|
|
26
|
+
- `Projects/Acme/Acme.md` + `Projects/Acme/SOW.md` (nested) — folder per entity with sub-documents
|
|
27
|
+
|
|
28
|
+
## Step 2: Sample Frontmatter
|
|
29
|
+
|
|
30
|
+
Read the first 25-30 lines of 2-3 files per directory to see what YAML frontmatter exists.
|
|
31
|
+
|
|
32
|
+
**Key things to look for:**
|
|
33
|
+
- Which fields are present (even if empty)
|
|
34
|
+
- Wikilink references: `client: "[[Acme Corp]]"` or `related_people: ["[[John Smith]]"]`
|
|
35
|
+
- Tag conventions: `tags: [project/active]`, `tags: ["#person"]`, `tags: [sop, operations]`
|
|
36
|
+
- Date formats: `date: 2026-01-15`, `start_date: 2026-01-15`
|
|
37
|
+
- Status encoding: frontmatter `status:` field vs tag-based `tags: [project/active]`
|
|
38
|
+
|
|
39
|
+
**Frontmatter vs no frontmatter:**
|
|
40
|
+
- Files WITH frontmatter (YAML between `---` fences) → use `frontmatter` extraction mode
|
|
41
|
+
- Files WITHOUT frontmatter (plain markdown) → use `unstructured` mode (LLM extraction, slower)
|
|
42
|
+
- If a directory has a mix, prefer `frontmatter` — files without frontmatter will be skipped, which is often acceptable
|
|
43
|
+
|
|
44
|
+
## Step 3: Map Directories to Entity Types
|
|
45
|
+
|
|
46
|
+
For each content directory, decide which Studiograph entity type it maps to. Use the directory name, file content, and frontmatter fields as signals.
|
|
47
|
+
|
|
48
|
+
### Entity Type Reference
|
|
49
|
+
|
|
50
|
+
**Project repo types** (time-bound, engagement-specific):
|
|
51
|
+
| Type | Use when | Key fields |
|
|
52
|
+
|------|----------|------------|
|
|
53
|
+
| `project` | Client engagements, initiatives | name, client, start_date, end_date, status, team |
|
|
54
|
+
| `meeting` | Meetings, events, conferences | name, date, attendees, agenda, action_items |
|
|
55
|
+
| `task` | Action items, tickets | name, assignee, due_date, status, priority |
|
|
56
|
+
| `deliverable` | Outputs, milestones | name, project, status, due_date |
|
|
57
|
+
| `brief` | Project briefs, RFPs | project_name, client, objectives |
|
|
58
|
+
| `artifact` | Files, documents, assets | name, type, project, url |
|
|
59
|
+
| `decision` | Architectural/business decisions | title, date, status, rationale |
|
|
60
|
+
|
|
61
|
+
**Function repo types** (operational, cross-project):
|
|
62
|
+
| Type | Use when | Key fields |
|
|
63
|
+
|------|----------|------------|
|
|
64
|
+
| `person` | People, contacts, team members | name, role, email, status, organization |
|
|
65
|
+
| `client` | Companies, organizations (as clients) | name, type, status, industry, contacts |
|
|
66
|
+
| `vendor` | Vendors, partners, freelancers | name, type, status, services |
|
|
67
|
+
| `deal` | Sales pipeline entries | name, client, stage, deal_value |
|
|
68
|
+
| `proposal` | Proposals, SOWs | name, client, status, deliverables |
|
|
69
|
+
| `contract` | Contracts, agreements | name, type, client, status |
|
|
70
|
+
| `financial-plan` | Budgets, rate cards, P&L | name, type, period |
|
|
71
|
+
| `role` | Job descriptions, org structure | title, department, level, type |
|
|
72
|
+
|
|
73
|
+
**Shared resource types** (reference, reusable):
|
|
74
|
+
| Type | Use when | Key fields |
|
|
75
|
+
|------|----------|------------|
|
|
76
|
+
| `process` | SOPs, workflows, methodologies | name, description, steps, owner |
|
|
77
|
+
| `standard` | Guidelines, conventions | name, category, guidelines |
|
|
78
|
+
| `template` | Reusable templates | name, category, template_content |
|
|
79
|
+
| `reference` | Articles, research, bookmarks | name, type, source, link |
|
|
80
|
+
| `technique` | Methods, frameworks | name, category, difficulty |
|
|
81
|
+
| `practice-area` | Service lines, capabilities | name, description, capabilities |
|
|
82
|
+
| `case-study` | Portfolio work, showcases | title, client, year, practice_areas |
|
|
83
|
+
|
|
84
|
+
### Common Obsidian Directory Mappings
|
|
85
|
+
|
|
86
|
+
These are patterns seen across vaults — adapt to the actual vault:
|
|
87
|
+
|
|
88
|
+
| Directory pattern | Likely entity type | Notes |
|
|
89
|
+
|-------------------|--------------------|-------|
|
|
90
|
+
| `Projects/` | `project` | May have sub-documents (see nested content below) |
|
|
91
|
+
| `People/`, `Contacts/` | `person` | Usually flat files |
|
|
92
|
+
| `Team/`, `Staff/` | `person` | Often richer frontmatter than external contacts |
|
|
93
|
+
| `Clients/`, `Companies/`, `Organizations/` | `client` | May have subdirectories by relationship type |
|
|
94
|
+
| `Meetings/`, `Meeting Notes/` | `meeting` | Date-prefixed filenames common |
|
|
95
|
+
| `Tasks/`, `Action Items/` | `task` | May overlap with a task manager integration |
|
|
96
|
+
| `SOPs/`, `Processes/`, `Workflows/` | `process` | Often has category/status/owner fields |
|
|
97
|
+
| `Areas/`, `Practice Areas/`, `Capabilities/` | `practice-area` | May lack frontmatter |
|
|
98
|
+
| `Case Studies/`, `Portfolio/`, `Work/` | `case-study` | Often has client, year, url fields |
|
|
99
|
+
| `Research/`, `References/`, `Resources/` | `reference` | Bookmarks, articles, links |
|
|
100
|
+
| `HR/`, `Roles/`, `Job Descriptions/` | `role` | Job postings, org structure |
|
|
101
|
+
| `Finances/`, `Finance/`, `Budgets/` | `financial-plan` | Rate cards, P&L, budgets |
|
|
102
|
+
| `Standards/`, `Guidelines/` | `standard` | Naming conventions, code standards |
|
|
103
|
+
| `Templates/` | `template` | Reusable document templates |
|
|
104
|
+
| `Proposals/`, `SOWs/` | `proposal` | Client proposals |
|
|
105
|
+
| `Contracts/` | `contract` | Agreements, NDAs |
|
|
106
|
+
| `Events/`, `Conferences/` | `meeting` | No dedicated event type — meeting is closest |
|
|
107
|
+
| `Emails/` | `artifact` | No dedicated email type |
|
|
108
|
+
| `Archive/` | same as active, disabled | Enable later if needed |
|
|
109
|
+
|
|
110
|
+
### Directories to Skip
|
|
111
|
+
|
|
112
|
+
- `.obsidian/` — Obsidian config
|
|
113
|
+
- `.smart-env/` — Smart Connections plugin data
|
|
114
|
+
- `Attachments/`, `Assets/`, `Media/` — binary files
|
|
115
|
+
- `Templates/` — often just scaffolding, not real entities (evaluate per vault)
|
|
116
|
+
- `Daily Notes/` — usually ephemeral, not entity-worthy
|
|
117
|
+
- `Clippings/` — web clippings, low signal
|
|
118
|
+
|
|
119
|
+
### Handling Nested Project Content
|
|
120
|
+
|
|
121
|
+
When a `Projects/` directory has subfolders with multiple files per project, ALL files get classified as the mapping's entity type. Sub-documents (meeting agendas, SOWs, concepts) become project entities.
|
|
122
|
+
|
|
123
|
+
**Options:**
|
|
124
|
+
1. **Accept and review** — the `studiograph review` step lets users fix misclassifications before committing
|
|
125
|
+
2. **Use `unstructured` mode** — the LLM can infer the correct entity type from content (slower, costs per file)
|
|
126
|
+
3. **Co-locate sub-files** — if sub-documents reference their parent project in frontmatter (e.g., `related_projects: ["[[My Project]]"]`), add `co_locate: { parent_field: "related_projects", subfolder: "notes" }` to write them as sub-content
|
|
127
|
+
|
|
128
|
+
## Step 4: Choose Extraction Mode Per Mapping
|
|
129
|
+
|
|
130
|
+
| Condition | Mode | Cost |
|
|
131
|
+
|-----------|------|------|
|
|
132
|
+
| Files have YAML frontmatter with useful fields | `frontmatter` | Free (no LLM) |
|
|
133
|
+
| Files are plain markdown, no frontmatter | `unstructured` | LLM call per file |
|
|
134
|
+
| Mix of both | `frontmatter` | Free — files without frontmatter are skipped |
|
|
135
|
+
| Small directory (<20 files) with no frontmatter | `unstructured` | Acceptable LLM cost |
|
|
136
|
+
| Large directory (100+) with no frontmatter | `frontmatter` or skip | `unstructured` would be expensive |
|
|
137
|
+
|
|
138
|
+
## Step 5: Build Field Maps
|
|
139
|
+
|
|
140
|
+
For each `frontmatter` mapping, build a `field_map` from the sampled YAML fields.
|
|
141
|
+
|
|
142
|
+
**Rules:**
|
|
143
|
+
- Keys are the Obsidian frontmatter field names (as they appear in the YAML)
|
|
144
|
+
- Values are the Studiograph entity field names (from the entity type reference above)
|
|
145
|
+
- Only map fields that actually exist in the frontmatter — don't invent mappings
|
|
146
|
+
- Wikilink fields (`"[[Entity Name]]"`) map naturally — the sync pipeline handles them
|
|
147
|
+
- Always include `tags` if the vault uses tags
|
|
148
|
+
- Use `id_from: "_filename"` and `content_from: "_body"` for all Obsidian mappings
|
|
149
|
+
|
|
150
|
+
**Common Obsidian frontmatter fields and their typical targets:**
|
|
151
|
+
|
|
152
|
+
| Obsidian field | Target field | Notes |
|
|
153
|
+
|----------------|-------------|-------|
|
|
154
|
+
| `title` / `name` | `name` or `title` | Entity display name |
|
|
155
|
+
| `status` | `status` | Map values with `status_map` if conventions differ |
|
|
156
|
+
| `client` | `client` | Often a wikilink |
|
|
157
|
+
| `date` | `date` | ISO date |
|
|
158
|
+
| `start_date` / `end_date` | `start_date` / `end_date` | Date range |
|
|
159
|
+
| `tags` | `tags` | Array of strings |
|
|
160
|
+
| `email` | `email` | |
|
|
161
|
+
| `role` / `title` (on person) | `role` | Obsidian often uses `title` for role |
|
|
162
|
+
| `related_people` | `contacts` or `attendees` | Usually wikilink array |
|
|
163
|
+
| `related_organizations` | `related_organizations` | Usually wikilink array |
|
|
164
|
+
| `related_projects` | `related_projects` | Usually wikilink array |
|
|
165
|
+
| `related_areas` | `related_areas` | Usually wikilink array |
|
|
166
|
+
| `url` / `website` | `website_url` or `link` | |
|
|
167
|
+
| `sectors` | `sectors` | Industry/domain tags |
|
|
168
|
+
| `practice_areas` | `practice_areas` | Service line references |
|
|
169
|
+
| `year` | `year` | For case studies |
|
|
170
|
+
|
|
171
|
+
## Step 6: Determine Target Repos
|
|
172
|
+
|
|
173
|
+
Check which repos exist in the workspace (`ls` the workspace directory or use `graph_list_repos`). Map entity types to existing repos:
|
|
174
|
+
|
|
175
|
+
| Entity types | Typical repo |
|
|
176
|
+
|-------------|-------------|
|
|
177
|
+
| project, case-study, deliverable, brief, artifact | `projects` |
|
|
178
|
+
| person, role | `people` |
|
|
179
|
+
| client, vendor | `clients` |
|
|
180
|
+
| meeting | `meetings` |
|
|
181
|
+
| process, standard, template, reference, technique, practice-area | A shared-resource repo if one exists, otherwise `projects` |
|
|
182
|
+
| deal, proposal, contract, financial-plan | A function repo if one exists, otherwise `projects` |
|
|
183
|
+
|
|
184
|
+
If a needed repo doesn't exist, the sync pipeline auto-creates it on `sync_apply`.
|
|
185
|
+
|
|
186
|
+
## Step 7: Write the Config
|
|
187
|
+
|
|
188
|
+
Generate `.studiograph/sources/obsidian.json` with all mappings. Present it to the user for review before writing.
|
|
189
|
+
|
|
190
|
+
**Template:**
|
|
191
|
+
```json
|
|
192
|
+
{
|
|
193
|
+
"name": "obsidian-<vault-name>",
|
|
194
|
+
"connector": "obsidian-<vault-name>",
|
|
195
|
+
"enabled": true,
|
|
196
|
+
"added_at": "<ISO timestamp>",
|
|
197
|
+
"entity_mappings": [
|
|
198
|
+
{
|
|
199
|
+
"source_type": "<descriptive-name>",
|
|
200
|
+
"entity_type": "<studiograph-type>",
|
|
201
|
+
"target_repo": "<repo-name>",
|
|
202
|
+
"extraction_mode": "frontmatter",
|
|
203
|
+
"enabled": true,
|
|
204
|
+
"directory_patterns": ["<VaultDir>/"],
|
|
205
|
+
"list_tool": "list_vault_files",
|
|
206
|
+
"read_tool": "get_vault_file",
|
|
207
|
+
"field_map": { ... },
|
|
208
|
+
"id_from": "_filename",
|
|
209
|
+
"content_from": "_body"
|
|
210
|
+
}
|
|
211
|
+
]
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Checklist before writing:**
|
|
216
|
+
- [ ] Every content directory has a mapping (or a reason to skip)
|
|
217
|
+
- [ ] `directory_patterns` use trailing slash and match the vault's exact directory names (case-sensitive)
|
|
218
|
+
- [ ] `list_tool` and `read_tool` are set to `"list_vault_files"` and `"get_vault_file"` for Obsidian
|
|
219
|
+
- [ ] Field maps only reference frontmatter fields that actually exist
|
|
220
|
+
- [ ] Directories with no frontmatter use `unstructured` mode or are skipped
|
|
221
|
+
- [ ] Subdirectories are handled (e.g., `Organizations/Clients/` not just `Organizations/`)
|
|
222
|
+
- [ ] `target_repo` values match existing repos or the user is aware new ones will be created
|
|
223
|
+
- [ ] Disabled mappings are marked `enabled: false` with a comment-like `source_type` explaining why
|
|
224
|
+
|
|
225
|
+
## Multiple Vaults
|
|
226
|
+
|
|
227
|
+
Each vault needs its own connector and source config. The MCP Tools binary is vault-specific — it connects to the Local REST API instance running in its vault.
|
|
228
|
+
|
|
229
|
+
1. Install both plugins (Local REST API + MCP Tools) in each vault
|
|
230
|
+
2. Create a connector per vault at `~/.studiograph/connectors/obsidian-<name>.json`, each pointing to that vault's `mcp-server` binary and API key
|
|
231
|
+
3. Create a source config per vault at `.studiograph/sources/obsidian-<name>.json` with directory patterns matching that vault's structure
|
|
232
|
+
4. Run `studiograph sync` (no arguments) to sync all enabled sources in one pass
|
|
233
|
+
|
|
234
|
+
**Port conflict:** Each vault's Local REST API runs on port 27124 by default. Only one vault can use a given port at a time. If both vaults need to be open simultaneously, change the port in one vault's Local REST API settings.
|
|
235
|
+
|
|
236
|
+
See `docs/obsidian-setup.md` for full connector setup and troubleshooting.
|
|
237
|
+
|
|
238
|
+
## After Setup
|
|
239
|
+
|
|
240
|
+
1. **Dry run:** `sync_run({ sources: ["obsidian"], dryRun: true })` — verify extraction counts look right
|
|
241
|
+
2. **Full run:** `sync_run({ sources: ["obsidian"] })` — extract to staging
|
|
242
|
+
3. **Review:** `sync_status` then `studiograph review` — spot-check entity types and field values
|
|
243
|
+
4. **Apply:** `sync_apply` — write entity files
|
|
244
|
+
5. **Commit:** `studiograph commit` — git commit across repos
|
|
245
|
+
|
|
246
|
+
See the `sync-setup` skill for the full sync workflow and the `sync-configuration` skill for field map syntax details.
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sync-configuration
|
|
3
|
+
description: Reference for building sync source configs — field maps, transforms, co-location, extraction modes
|
|
4
|
+
loading: eager
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Sync Configuration Reference
|
|
8
|
+
|
|
9
|
+
Use this reference when helping users build or modify source configs at `.studiograph/sources/<name>.json`.
|
|
10
|
+
|
|
11
|
+
## Source Config Structure
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"name": "linear",
|
|
16
|
+
"connector": "linear",
|
|
17
|
+
"enabled": true,
|
|
18
|
+
"added_at": "2026-02-15T10:00:00.000Z",
|
|
19
|
+
"entity_mappings": [ ... ],
|
|
20
|
+
"field_priority": { "email": "pipedrive" }
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- `connector` references a connector in `~/.studiograph/connectors/`
|
|
25
|
+
- `field_priority` — optional per-field merge priority when multiple sources write the same entity
|
|
26
|
+
- `entity_mappings` — array of mappings, each maps one external entity type to a Studiograph type
|
|
27
|
+
|
|
28
|
+
## Entity Mapping Fields
|
|
29
|
+
|
|
30
|
+
| Field | Required | Description |
|
|
31
|
+
|-------|----------|-------------|
|
|
32
|
+
| `source_type` | Yes | What the source calls this type (e.g. `"deal"`, `"issue"`) |
|
|
33
|
+
| `entity_type` | Yes | Studiograph type (e.g. `"project"`, `"task"`, `"meeting"`) |
|
|
34
|
+
| `target_repo` | Yes | Repo to write to (e.g. `"projects"`) |
|
|
35
|
+
| `extraction_mode` | Yes | `"structured"`, `"frontmatter"`, or `"unstructured"` |
|
|
36
|
+
| `id_from` | No | Source field for entity_id (default `"title"`, or `"_filename"` for frontmatter mode) |
|
|
37
|
+
| `content_from` | No | Source field for markdown body (or `"_body"` for frontmatter mode) |
|
|
38
|
+
| `field_map` | No | Maps source fields to entity fields (see Field Map Syntax) |
|
|
39
|
+
| `status_map` | No | Maps source status values to entity statuses (case-insensitive) |
|
|
40
|
+
| `fetch_details` | No | Fetch full record per listed ID (for sparse list APIs) |
|
|
41
|
+
| `list_limit` | No | Override limit param for list tool |
|
|
42
|
+
| `list_params` | No | Extra params for list tool. Pass array for multiple list calls merged |
|
|
43
|
+
| `directory_patterns` | No | Directory patterns for file sources (frontmatter/unstructured) |
|
|
44
|
+
| `write_mode` | No | `"entity"` (default, `id/main.md` folder) or `"collection"` (flat `id.md` file) |
|
|
45
|
+
| `co_locate` | No | Co-locate as sub-content inside parent entity folder |
|
|
46
|
+
| `list_tool` | No | Explicit MCP tool name for listing records (bypasses heuristic matching) |
|
|
47
|
+
| `read_tool` | No | Explicit MCP tool name for reading records (bypasses heuristic matching) |
|
|
48
|
+
|
|
49
|
+
## Extraction Modes
|
|
50
|
+
|
|
51
|
+
- **`structured`** — API JSON → field_map → frontmatter. No LLM. For Pipedrive, Linear, Granola, Asana.
|
|
52
|
+
- **`frontmatter`** — Markdown files with YAML → field_map. No LLM. For Obsidian. Supports `_filename` and `_body` sentinels.
|
|
53
|
+
- **`unstructured`** — Freeform text → LLM extraction. Slow, expensive. Last resort when no structured metadata exists.
|
|
54
|
+
|
|
55
|
+
## Field Map Syntax
|
|
56
|
+
|
|
57
|
+
Keys are source field paths, values are entity field names or FieldTransform objects.
|
|
58
|
+
|
|
59
|
+
**Simple string:** `"title": "name"` — direct copy
|
|
60
|
+
**Dot-notation:** `"org_id.name": "organization"` — nested access
|
|
61
|
+
**Array index:** `"email[0].value": "email"` — specific array element
|
|
62
|
+
**FieldTransform object:**
|
|
63
|
+
```json
|
|
64
|
+
{ "org_name": { "field": "client", "transform": "wikilink" } }
|
|
65
|
+
```
|
|
66
|
+
FieldTransform fields: `field` (target name), `transform` (transform type), `subfield` (optional — extract nested path from each array element before transforming)
|
|
67
|
+
|
|
68
|
+
### Subfield example
|
|
69
|
+
Source returns: `[{ "details": { "person": { "name": "Alice" } } }, ...]`
|
|
70
|
+
Config: `{ "field": "attendees", "transform": "wikilink-array", "subfield": "details.person.name" }`
|
|
71
|
+
Result: `["[[alice]]", ...]`
|
|
72
|
+
|
|
73
|
+
## Transforms
|
|
74
|
+
|
|
75
|
+
| Transform | Input | Output |
|
|
76
|
+
|-----------|-------|--------|
|
|
77
|
+
| `direct` | `"hello"` | `"hello"` (passthrough) |
|
|
78
|
+
| `kebab-case` | `"Acme Corp"` | `"acme-corp"` |
|
|
79
|
+
| `date-iso` | `"2026-02-20T14:30:00Z"` | `"2026-02-20"` |
|
|
80
|
+
| `wikilink` | `"Acme Corp"` | `"[[acme-corp]]"` |
|
|
81
|
+
| `wikilink-array` | `["Alice", "Bob"]` | `["[[alice]]", "[[bob]]"]` |
|
|
82
|
+
|
|
83
|
+
## Co-Location
|
|
84
|
+
|
|
85
|
+
Writes entities as sub-content files inside a parent entity folder instead of standalone entity folders.
|
|
86
|
+
|
|
87
|
+
**Config:** Add `co_locate` to a mapping:
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"co_locate": { "parent_field": "project", "subfolder": "tasks" },
|
|
91
|
+
"field_map": { "project": { "field": "project", "transform": "wikilink" } }
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Result path:** `{target_repo}/{parent_id}/{subfolder}/{entity_id}.md`
|
|
96
|
+
Example: `projects/cooper-hewitt-brand-refresh/tasks/sch-101.md`
|
|
97
|
+
|
|
98
|
+
**Rules:**
|
|
99
|
+
- `parent_field` must be a wikilink target in `field_map` so the reference is available
|
|
100
|
+
- Entities without a parent value are **skipped** (not an error)
|
|
101
|
+
- Co-located files are sub-content, not graph entities (no `entity_id/main.md` folder)
|
|
102
|
+
- `target_repo` should be the repo where the **parent** entities live
|
|
103
|
+
|
|
104
|
+
## Write Mode
|
|
105
|
+
|
|
106
|
+
Controls how entities are written to disk:
|
|
107
|
+
|
|
108
|
+
- **`entity`** (default) — `repo/entity-id/main.md` folder. Fully indexed, supports sub-content. Use for core types (projects, clients, people).
|
|
109
|
+
- **`collection`** — `repo/entity-id.md` flat file. Simpler, no folder overhead. Use for high-volume types (meetings, notes, references).
|
|
110
|
+
|
|
111
|
+
## Explicit MCP Tool Selection
|
|
112
|
+
|
|
113
|
+
For file-based sources (frontmatter, unstructured), add `list_tool` and `read_tool` when the connector's tool names don't follow predictable patterns:
|
|
114
|
+
```json
|
|
115
|
+
{ "list_tool": "list_vault_files", "read_tool": "get_vault_file" }
|
|
116
|
+
```
|
|
117
|
+
When omitted, the pipeline uses heuristic matching (looking for tools containing "list", "read", "get", etc.).
|
|
118
|
+
|
|
119
|
+
## Sentinels (frontmatter mode only)
|
|
120
|
+
|
|
121
|
+
- `_filename` in `id_from` — entity ID from the file's name (slugified, `.md` stripped)
|
|
122
|
+
- `_body` in `content_from` — markdown body from file content below the `---` frontmatter fence
|
|
123
|
+
|
|
124
|
+
## Built-in Definitions
|
|
125
|
+
|
|
126
|
+
| Source | Mappings | Notes |
|
|
127
|
+
|--------|----------|-------|
|
|
128
|
+
| **Pipedrive** | deal→project, person→person, org→client | Ready to sync |
|
|
129
|
+
| **Granola** | document→meeting | `fetch_details: true`, `list_limit: 1000` |
|
|
130
|
+
| **Linear** | issue→task (co-located under projects), project→project | Issues use `co_locate` |
|
|
131
|
+
| **Asana** | task→task, project→project | Needs `list_params: { workspace: "GID" }` |
|
|
132
|
+
| **Obsidian** | Example mappings only (`.template` file) | Needs customization per vault |
|
|
133
|
+
|
|
134
|
+
## Configuration Patterns
|
|
135
|
+
|
|
136
|
+
**Adding co-location to any mapping:** Add `co_locate: { parent_field, subfolder }` and ensure `parent_field` is a wikilink target in `field_map`.
|
|
137
|
+
|
|
138
|
+
**Multiple list calls:** Set `list_params` as an array: `[{ workspace: "123", archived: false }, { workspace: "123", archived: true }]`
|
|
139
|
+
|
|
140
|
+
**Custom source (no built-in):** Create a source config with `entity_mappings` from scratch. Choose extraction_mode, define field_map targeting entity schema fields, set target_repo.
|
|
141
|
+
|
|
142
|
+
**Overriding built-in defaults:** Pass custom `entity_mappings` to `sync_setup_source` — they replace the defaults entirely. Or edit `.studiograph/sources/<name>.json` directly.
|
|
143
|
+
|
|
144
|
+
**Status maps:** Map source status strings (case-insensitive) to Studiograph enums. Common patterns: Pipedrive (`won→completed, lost→archived, open→active`), Linear issues (`Backlog→open, In Progress→in-progress, Done→done, Canceled→cancelled`).
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sync-setup
|
|
3
|
+
description: Guide for setting up and running entity sync from external sources
|
|
4
|
+
loading: eager
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Entity Sync
|
|
8
|
+
|
|
9
|
+
You can sync data from external sources (Linear, Pipedrive, Granola, Obsidian, etc.) into the knowledge graph using the sync tools.
|
|
10
|
+
|
|
11
|
+
## First-Time Setup
|
|
12
|
+
|
|
13
|
+
1. **Check what's available:** Call `sync_list_sources` immediately — it returns configured sources (with full entity_mappings), available connectors, and known source definitions
|
|
14
|
+
2. **Verify the connector exists** — connectors hold API credentials and are CLI-only for security. If missing, tell the user:
|
|
15
|
+
> "You'll need to set up the connector first. Run `studiograph connector add <name>` in your terminal."
|
|
16
|
+
3. **Add the source:** `sync_setup_source({ name: "linear" })` — uses default mappings from built-in definitions when available
|
|
17
|
+
4. **Customize if needed:** Built-in definitions (Pipedrive, Granola, Linear, Asana) provide ready-to-use defaults. To customize, pass `entity_mappings` to `sync_setup_source` to override field maps, add co-location, change target repos, or add status maps. See the `sync-configuration` skill for field map syntax and options.
|
|
18
|
+
5. **No built-in definition?** Use `sync_inspect_connector` to discover the connector's tools and syncable entity types, then `sync_sample_data` to fetch a sample record and see field shapes. Build `entity_mappings` from the field analysis. See below and the `sync-configuration` skill for the full mapping schema.
|
|
19
|
+
6. **Run the sync:** `sync_run({ sources: ["linear"] })`
|
|
20
|
+
7. **Review staging:** `sync_status` — show the user what will be committed
|
|
21
|
+
8. **Apply on confirmation:** Only call `sync_apply` after the user approves
|
|
22
|
+
9. **Review & commit:** `studiograph review` (interactive diff review with approve/reject per entity), then `studiograph commit` (git commit across all repos)
|
|
23
|
+
|
|
24
|
+
## Building a Config from Scratch (no built-in definition)
|
|
25
|
+
|
|
26
|
+
When a connector has no built-in source definition, use introspection to auto-discover the data model:
|
|
27
|
+
|
|
28
|
+
1. `sync_inspect_connector({ connector: "myservice" })` — lists all tools categorized by purpose, detects syncable entity types with list/get tool pairs
|
|
29
|
+
2. Pick which entity types to sync from the `syncableTypes` results
|
|
30
|
+
3. `sync_sample_data({ connector: "myservice", tool: "list_records" })` — fetches one record and analyzes field shapes. Returns field paths, types, sample values, and suggested field_map entries
|
|
31
|
+
4. Build `entity_mappings` using the field analysis — map source fields to entity schema fields using dot notation for nested fields
|
|
32
|
+
5. `sync_setup_source({ name: "myservice", entity_mappings: [...] })` — save the config
|
|
33
|
+
|
|
34
|
+
**Tips:**
|
|
35
|
+
- `sync_sample_data` auto-sets `limit: 1` — you don't need to pass it
|
|
36
|
+
- Use the `suggestedFieldMap` from the response as a starting point
|
|
37
|
+
- Nested fields use dot notation in field_map keys (e.g. `"org_id.name": "organization"`)
|
|
38
|
+
- Call `sync_sample_data` for each entity type you plan to sync
|
|
39
|
+
|
|
40
|
+
## Modifying an Existing Source
|
|
41
|
+
|
|
42
|
+
When a user asks to adjust, change, or view a source config, **immediately call `sync_list_sources`** to read the current configuration. Do not ask the user to paste the config — you can read it yourself.
|
|
43
|
+
|
|
44
|
+
1. `sync_list_sources` — call this FIRST, before asking questions (returns full `entity_mappings` with field maps, transforms, etc.)
|
|
45
|
+
2. Show the user the relevant parts of their config and ask what they want to change
|
|
46
|
+
3. Build the updated `entity_mappings` array (you must pass the complete array — it replaces, not merges)
|
|
47
|
+
4. `sync_setup_source({ name: "...", entity_mappings: [...], force: true })` — overwrite with updated config
|
|
48
|
+
|
|
49
|
+
Common adjustments: changing `field_map` entries, adding/removing entity mappings, changing `target_repo`, adding `co_locate`, switching `write_mode`, adjusting `status_map`, adding `list_tool`/`read_tool`.
|
|
50
|
+
|
|
51
|
+
## Repeat Sync Flow
|
|
52
|
+
|
|
53
|
+
1. `sync_run({ incremental: true })` — only fetches records updated since last sync
|
|
54
|
+
2. `sync_status` — present the summary
|
|
55
|
+
3. Wait for user confirmation
|
|
56
|
+
4. `sync_apply` — writes entity files (no git commit)
|
|
57
|
+
5. `workspace_status` — show what files changed across repos
|
|
58
|
+
6. `workspace_review` — show diffs (optionally filter by `entityType`)
|
|
59
|
+
7. `workspace_commit({ messagePrefix: "sync" })` — git commits across repos (or let user run `studiograph commit`)
|
|
60
|
+
|
|
61
|
+
## Post-Apply Results
|
|
62
|
+
|
|
63
|
+
After `sync_apply`, explain what happened to the user:
|
|
64
|
+
|
|
65
|
+
- **Standard entities** are written as: `{target_repo}/{entity_id}/main.md` (entity folder with sentinel file)
|
|
66
|
+
- **Co-located entities** are written as: `{target_repo}/{parent_id}/{subfolder}/{entity_id}.md` (flat file inside parent folder). Co-located files are sub-content, not graph entities.
|
|
67
|
+
- **Skipped entities** — when co-location is configured but the parent field is empty or missing, those entities are skipped (not an error)
|
|
68
|
+
- **Auto-registered repos** — if a `target_repo` doesn't exist yet, it's automatically created and registered in the workspace
|
|
69
|
+
|
|
70
|
+
## Troubleshooting
|
|
71
|
+
|
|
72
|
+
- **"Uncommitted changes"** — sync requires a clean working tree. Tell the user to commit or stash changes first, or use `--force` to override
|
|
73
|
+
- **"Connector not found"** — the connector isn't set up. User must run `studiograph connector add <name>` in terminal
|
|
74
|
+
- **Entities skipped during apply** — for co-located entities, check that the `parent_field` has a value in the extracted frontmatter. Missing parent = skip.
|
|
75
|
+
- **Obsidian template file** — Obsidian creates a `.template` file instead of default mappings (every vault is different). Tell the user to copy mappings from the template into the source config and adjust `directory_patterns` and `field_map` for their vault.
|
|
76
|
+
|
|
77
|
+
## Important Rules
|
|
78
|
+
|
|
79
|
+
- **Never auto-commit** — always show `sync_status` and get user confirmation before `sync_apply`
|
|
80
|
+
- **Connector management is CLI-only** — API keys and tokens must be set up via `studiograph connector add/remove`. Never ask users to provide API keys in chat
|
|
81
|
+
- **Use incremental for repeat syncs** — avoids re-processing unchanged records
|
|
82
|
+
- **Use dry run for previews** — `sync_run({ dryRun: true })` shows what would be extracted without writing staging
|
|
83
|
+
- **Abort if needed** — `sync_abort` clears staging if the user wants to start over
|
|
84
|
+
- **sync_commit is deprecated** — use `sync_apply` then `workspace_commit` instead
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* On-demand connector tools
|
|
3
|
+
*
|
|
4
|
+
* Instead of registering hundreds of individual MCP connector tools with the
|
|
5
|
+
* agent (which bloats every API call), this module provides two lightweight
|
|
6
|
+
* proxy tools:
|
|
7
|
+
*
|
|
8
|
+
* connector_list — discover available connectors and their tools
|
|
9
|
+
* connector_call — route a call to a specific connector tool
|
|
10
|
+
*
|
|
11
|
+
* The actual MCP tool wrappers are stored in a registry built from
|
|
12
|
+
* ConnectorManager.buildTools() output.
|
|
13
|
+
*/
|
|
14
|
+
export interface ConnectorToolEntry {
|
|
15
|
+
/** Namespaced name: "pipedrive__deals_search" */
|
|
16
|
+
name: string;
|
|
17
|
+
/** Local name within the connector: "deals_search" */
|
|
18
|
+
localName: string;
|
|
19
|
+
/** Connector name: "pipedrive" */
|
|
20
|
+
connector: string;
|
|
21
|
+
description: string;
|
|
22
|
+
parameters: any;
|
|
23
|
+
execute: (toolCallId: string, params: any) => Promise<any>;
|
|
24
|
+
}
|
|
25
|
+
export interface ConnectorRegistry {
|
|
26
|
+
connectors: Map<string, ConnectorToolEntry[]>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Build a registry from ConnectorManager's wrapped tool objects.
|
|
30
|
+
* Parses the namespaced tool names (e.g. "pipedrive__deals_search")
|
|
31
|
+
* into connector → tool[] groupings.
|
|
32
|
+
*/
|
|
33
|
+
export declare function buildConnectorRegistry(tools: any[]): ConnectorRegistry;
|
|
34
|
+
/**
|
|
35
|
+
* Create two proxy tools for on-demand connector access.
|
|
36
|
+
*/
|
|
37
|
+
export declare function createConnectorTools(registry: ConnectorRegistry): any[];
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* On-demand connector tools
|
|
3
|
+
*
|
|
4
|
+
* Instead of registering hundreds of individual MCP connector tools with the
|
|
5
|
+
* agent (which bloats every API call), this module provides two lightweight
|
|
6
|
+
* proxy tools:
|
|
7
|
+
*
|
|
8
|
+
* connector_list — discover available connectors and their tools
|
|
9
|
+
* connector_call — route a call to a specific connector tool
|
|
10
|
+
*
|
|
11
|
+
* The actual MCP tool wrappers are stored in a registry built from
|
|
12
|
+
* ConnectorManager.buildTools() output.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Build a registry from ConnectorManager's wrapped tool objects.
|
|
16
|
+
* Parses the namespaced tool names (e.g. "pipedrive__deals_search")
|
|
17
|
+
* into connector → tool[] groupings.
|
|
18
|
+
*/
|
|
19
|
+
export function buildConnectorRegistry(tools) {
|
|
20
|
+
const connectors = new Map();
|
|
21
|
+
for (const tool of tools) {
|
|
22
|
+
const sep = tool.name.indexOf('__');
|
|
23
|
+
const connector = sep !== -1 ? tool.name.slice(0, sep) : tool.name;
|
|
24
|
+
const localName = sep !== -1 ? tool.name.slice(sep + 2) : tool.name;
|
|
25
|
+
if (!connectors.has(connector))
|
|
26
|
+
connectors.set(connector, []);
|
|
27
|
+
connectors.get(connector).push({
|
|
28
|
+
name: tool.name,
|
|
29
|
+
localName,
|
|
30
|
+
connector,
|
|
31
|
+
description: tool.description ?? '',
|
|
32
|
+
parameters: tool.parameters,
|
|
33
|
+
execute: tool.execute,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return { connectors };
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Create two proxy tools for on-demand connector access.
|
|
40
|
+
*/
|
|
41
|
+
export function createConnectorTools(registry) {
|
|
42
|
+
return [
|
|
43
|
+
{
|
|
44
|
+
name: 'connector_list',
|
|
45
|
+
description: 'List available external connectors and their tools. Call with no arguments to see all connectors, or with connector name to see its tools, or with both connector and tool to see a tool\'s parameter schema.',
|
|
46
|
+
parameters: {
|
|
47
|
+
type: 'object',
|
|
48
|
+
properties: {
|
|
49
|
+
connector: {
|
|
50
|
+
type: 'string',
|
|
51
|
+
description: 'Show tools for this connector (e.g. "pipedrive", "linear")',
|
|
52
|
+
},
|
|
53
|
+
tool: {
|
|
54
|
+
type: 'string',
|
|
55
|
+
description: 'Show the parameter schema for this specific tool',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
execute: async (_toolCallId, params) => {
|
|
60
|
+
// Specific tool schema
|
|
61
|
+
if (params.connector && params.tool) {
|
|
62
|
+
const tools = registry.connectors.get(params.connector);
|
|
63
|
+
if (!tools) {
|
|
64
|
+
return { content: [{ type: 'text', text: `Connector "${params.connector}" not found. Available: ${[...registry.connectors.keys()].join(', ')}` }] };
|
|
65
|
+
}
|
|
66
|
+
const tool = tools.find(t => t.localName === params.tool);
|
|
67
|
+
if (!tool) {
|
|
68
|
+
return { content: [{ type: 'text', text: `Tool "${params.tool}" not found in ${params.connector}.` }] };
|
|
69
|
+
}
|
|
70
|
+
return { content: [{ type: 'text', text: `${params.connector} / ${params.tool}\n${tool.description}\n\nParameters:\n${JSON.stringify(tool.parameters, null, 2)}` }] };
|
|
71
|
+
}
|
|
72
|
+
// Tools for a specific connector
|
|
73
|
+
if (params.connector) {
|
|
74
|
+
const tools = registry.connectors.get(params.connector);
|
|
75
|
+
if (!tools) {
|
|
76
|
+
return { content: [{ type: 'text', text: `Connector "${params.connector}" not found. Available: ${[...registry.connectors.keys()].join(', ')}` }] };
|
|
77
|
+
}
|
|
78
|
+
const list = tools.map(t => `- ${t.localName}: ${t.description}`).join('\n');
|
|
79
|
+
return { content: [{ type: 'text', text: `${params.connector} (${tools.length} tools):\n${list}` }] };
|
|
80
|
+
}
|
|
81
|
+
// All connectors overview
|
|
82
|
+
const summary = [...registry.connectors.entries()]
|
|
83
|
+
.map(([name, tools]) => `- ${name} (${tools.length} tools)`)
|
|
84
|
+
.join('\n');
|
|
85
|
+
return { content: [{ type: 'text', text: `Available connectors:\n${summary}\n\nCall with connector to see available tools.` }] };
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: 'connector_call',
|
|
90
|
+
description: 'Call a tool on an external service (Pipedrive, Linear, Granola, Asana, Obsidian). Use connector_list first to discover available tools and their parameters.',
|
|
91
|
+
parameters: {
|
|
92
|
+
type: 'object',
|
|
93
|
+
properties: {
|
|
94
|
+
connector: {
|
|
95
|
+
type: 'string',
|
|
96
|
+
description: 'Connector name (e.g. "pipedrive", "linear", "granola")',
|
|
97
|
+
},
|
|
98
|
+
tool: {
|
|
99
|
+
type: 'string',
|
|
100
|
+
description: 'Tool name within the connector (e.g. "deals_search", "list_issues")',
|
|
101
|
+
},
|
|
102
|
+
arguments: {
|
|
103
|
+
type: 'object',
|
|
104
|
+
description: 'Arguments to pass to the tool',
|
|
105
|
+
additionalProperties: true,
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
required: ['connector', 'tool'],
|
|
109
|
+
},
|
|
110
|
+
execute: async (_toolCallId, params) => {
|
|
111
|
+
const tools = registry.connectors.get(params.connector);
|
|
112
|
+
if (!tools) {
|
|
113
|
+
return {
|
|
114
|
+
content: [{ type: 'text', text: `Connector "${params.connector}" not found. Available: ${[...registry.connectors.keys()].join(', ')}` }],
|
|
115
|
+
isError: true,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const tool = tools.find(t => t.localName === params.tool);
|
|
119
|
+
if (!tool) {
|
|
120
|
+
const available = tools.slice(0, 20).map(t => t.localName).join(', ');
|
|
121
|
+
const suffix = tools.length > 20 ? ` ... and ${tools.length - 20} more` : '';
|
|
122
|
+
return {
|
|
123
|
+
content: [{ type: 'text', text: `Tool "${params.tool}" not found in ${params.connector}. Available: ${available}${suffix}` }],
|
|
124
|
+
isError: true,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
return tool.execute(_toolCallId, params.arguments || {});
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
];
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=connector-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connector-tools.js","sourceRoot":"","sources":["../../../src/agent/tools/connector-tools.ts"],"names":[],"mappings":"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"}
|