Fabric (fabric.so) connector for AskMyDocs — API-key + workspace-id auth, cursor-paginated note sync. OAuth2 path stubbed pending fabric.so GA.
Drop-in Laravel package. composer require it from any AskMyDocs install and the Fabric connector appears in the admin UI on the next request.
⚠️ Note: this is the Fabric.so connector — the AI-native knowledge tool at https://fabric.so. It is not the Microsoft Fabric data-platform connector.
- Why this package
- Features
- AI vibe-coding pack included
- Architecture at a glance
- Installation
- Credential setup (junior-proof, step by step)
- Activation inside AskMyDocs
- Sync semantics
- What gets ingested
- Testing
- Live testsuite
- Troubleshooting
- Roadmap
- License
AskMyDocs is an enterprise-grade RAG + canonical knowledge compilation system. Out of the box it ingests markdown from disk, the chat UI, an HTTP API, and a Git-driven workflow — but a lot of personal-knowledge work increasingly lives in Fabric.so.
This package is the smallest possible surface for shipping that integration:
- A
FabricConnectorthat implementsPadosoft\AskMyDocsConnectorBase\ConnectorInterface. - API-key + optional workspace-id auth — works with both Personal API Keys and Developer API Keys today.
- Cursor-paginated note sync recognising both
next_cursorandpagination.nextresponse envelopes Fabric documents. - OAuth2 surface stubbed behind a config flag — when fabric.so ships OAuth2 GA, flip
oauth_enabled = trueand the OAuth path activates automatically. - A composer.json that auto-registers via
extra.askmydocs.connectors. Zero edits to your host app's config required.
composer require padosoft/askmydocs-connector-fabric. Done.
- 🔌 Zero-config installation — composer-extra discovery auto-registers the connector at boot.
- 🔑 API-key auth today, OAuth2-ready tomorrow — supports both Personal + Developer API Keys with optional
X-Fabric-Workspace-Idheader. OAuth2 path stubbed; flip a config flag when fabric.so GAs OAuth. - ♻️ Incremental sync — Fabric's
updated_afterfilter (when honoured by the listing endpoint); falls back to full sweep client-side. - 🚦 Cursor pagination — walks
next_cursorANDpagination.nextenvelopes per Fabric's partial OpenAPI. - 🧠 Source-aware metadata — note id, workspace id, collection id, AI annotations, tags all surface to the host's reranker via
SourceAwareMetadataBuilder. - 🚦 Failure-loud exception taxonomy — 401 / 403 →
ConnectorAuthException, other non-2xx →ConnectorApiException. Non-JSON bodies and missing credentials raise typed errors instead of silent skips. - 🏢 Per-tenant isolated — every credential read and ingestion dispatch is scoped to the active
TenantContext. Per-tenant credentials live in the installation'sconfig_json. - 🧪 Test-friendly —
Http::fake()feature tests against the spy ingestion contract; opt-in live test that hits realapi.fabric.sowhenCONNECTOR_FABRIC_LIVE=1.
This package was built with a vibe-coding pack of Claude Code skills and rules (.claude/ directory in the parent AskMyDocs repo) that codify the architectural invariants — the IoC contract that keeps this package standalone-agnostic, Fabric's dual-envelope pagination quirk, the failure-loud exception taxonomy, the API-key vs OAuth dual surface.
If you're using Claude Code to fork or extend this package, point the agent at the parent repo's .claude/ pack and it stays inside the invariants automatically. No tribal-knowledge drift.
┌──────────────────────────────┐
Composer │ padosoft/askmydocs- │
require ───────▶│ connector-fabric │
│ (this package) │
└────────────┬─────────────────┘
│
│ auto-registered via composer
│ extra.askmydocs.connectors
▼
┌──────────────────────────────┐
│ padosoft/askmydocs-connector-│
│ base v1.1.1+ │
│ ConnectorRegistry │
└────────────┬─────────────────┘
│
│ resolves FabricConnector
▼
┌──────────────────────────────┐
│ FabricConnector::syncFull │
│ • GET /v2/notes (cursor) │
│ • GET /v2/notes/{id} │
│ • SourceAwareMetadata │
└────────────┬─────────────────┘
│
│ ConnectorIngestionContract
│ (IoC bridge — host implements)
▼
┌──────────────────────────────┐
│ Host app (AskMyDocs): │
│ • Storage::put → KB disk │
│ • IngestDocumentJob │
│ • kb_canonical_audit row │
│ • PII redactor at boundary │
└──────────────────────────────┘
The IoC bridge is the key design decision: this package never imports any host class. It dispatches every host-side concern through Padosoft\AskMyDocsConnectorBase\Contracts\ConnectorIngestionContract. The host binds its own implementation in a service provider; this package stays standalone-agnostic.
composer require padosoft/askmydocs-connector-fabricThe package follows Laravel's auto-discovery convention. After install:
php artisan vendor:publish --tag=connector-fabric-config # optional — for env-var overrides
php artisan vendor:publish --tag=connector-fabric-assets # optional — copies fabric.svg to public/connectorsThe connector-base migrations ship in the parent package and auto-load via its service provider; no extra migrate step is needed.
Fabric.so uses API-key auth today. The flow is much shorter than OAuth-based connectors — there's no callback URL to register and no "share with integration" step.
- Open https://fabric.so in your browser. Create an account or sign in.
- From your workspace home, click your avatar (top-right) → Settings → Developers (or visit https://developers.fabric.so).
Pick the key type that matches your use case:
- Personal API Key — grants access to YOUR notes. Use this for single-tenant deployments or when an admin is ingesting their own knowledge base.
- Developer API Key — grants delegated access to a specific workspace (requires a workspace id). Use this for multi-tenant deployments where each tenant brings their own workspace.
Click "Generate API Key" → label it AskMyDocs ingest → confirm. Copy the key value (it will only display once).
If you generated a Developer API Key, also copy the Workspace ID displayed alongside it. Personal API Keys do not need this field.
In your AskMyDocs host app's .env:
CONNECTOR_FABRIC_API_KEY=<your-personal-or-developer-api-key>
# Only needed for Developer API Keys:
# CONNECTOR_FABRIC_WORKSPACE_ID=<your-workspace-id>
# Override only if Fabric ships a regional API base; defaults to https://api.fabric.so:
# CONNECTOR_FABRIC_API_BASE=https://api.fabric.soFor multi-tenant deployments, prefer the admin UI's Install flow — it lets each tenant supply their own API key in the installation's config_json instead of leaking a single env-level key across tenants.
curl -s https://api.fabric.so/v2/users/me \
-H "X-Api-Key: <your-api-key>" \
-H "Accept: application/json"Expected: 200 OK with a JSON user payload. If you see 401 unauthorized → re-copy the key from step 2 (it might have been truncated). If you see 403 forbidden → the key is for a different workspace; pass the right X-Fabric-Workspace-Id.
401 unauthorized— Key invalid, revoked, or copy-paste error (Fabric keys are long; verify no whitespace was clipped).403 forbidden— Developer API key without a matching workspace-id header. AddCONNECTOR_FABRIC_WORKSPACE_ID.429 rate_limited— Fabric enforces per-key rate limits; the connector retries with exponential back-off via Laravel's HTTP client defaults.
After composer require + the env vars above:
- Run the host app's admin UI.
- Navigate to Settings → Connectors.
- The Fabric card appears with an Install button.
- Click Install → the admin prompts for the API key (and optional workspace id) → status flips to
active. - The first full sync fires within the cadence window. To trigger immediately, click Sync now.
- Full sync —
GET /v2/notes?limit=50, walksnext_cursor/pagination.nextuntil empty. Each note is fetched (list payload first, follow-upGET /v2/notes/{id}when the list doesn't carry the body),content_markdownpreferred overcontent, dispatched via the IoC contract. Safety cap at 200 pagination iterations. - Incremental sync — same listing with
updated_after=<ISO8601>query parameter. When the watermark isnull, falls back to a full sync. - Deletion reconciliation — Fabric's API does NOT yet expose a deleted-state surface on the listing endpoint as of v2026-05-12. When upstream adds one, the connector will route deletions through
ConnectorIngestionContract::softDeleteByRemoteId('fabric_note_id', ...). Until then, deletions are not automatically reconciled — operators run a full sync to detect orphans. - Disconnect — clears local credentials only. Fabric has no programmatic API-key revoke endpoint; operators rotate the key at https://developers.fabric.so for full revocation. The audit metadata carries that hint.
For every Fabric note the integration can see:
- Markdown body —
content_markdownwhen present, otherwisecontentplain-text fallback. Title prepended as# Titleso the host's chunker indexes it. - Frontmatter / metadata captured under
metadata.converter_hints.fabric:note_id,workspace_id,collection_idupdated_at(ISO timestamp)ai_annotations(the Fabric-generated AI summaries / extractions)tags— normalised to a flat list of names regardless of upstream shape (string or object).
_derivedreranker signals undermetadata.converter_hints._derived:search_tags,recency_bucket
The synthetic MIME application/vnd.fabric.note+json routes the document to the host's Fabric-aware chunker when one is installed.
composer install
vendor/bin/phpunitThe suite has two flavours:
| Suite | What it covers | Network |
|---|---|---|
| Feature | FabricConnector against Http::fake() and the spy ingestion contract — ~18 scenarios incl. pagination envelopes, auth failures, empty content, tag normalisation, OAuth-stub error. |
None |
| Live | Opt-in — actually hits api.fabric.so. Skipped unless CONNECTOR_FABRIC_LIVE=1. |
Real |
CI runs Default (Feature) against PHP 8.3 / 8.4 / 8.5 × Laravel 12 / 13.
export CONNECTOR_FABRIC_LIVE=1
export CONNECTOR_FABRIC_API_KEY=<your-api-key>
# Optional — only for Developer API Keys:
# export CONNECTOR_FABRIC_WORKSPACE_ID=<your-workspace-id>
vendor/bin/phpunit --testsuite=LiveThis calls /v2/users/me once to validate credentials. The /v2/notes listing surface is exercised by the Feature suite with Http::fake().
| Symptom | Likely cause | Fix |
|---|---|---|
No Fabric API key configured |
No api_key in installation's config_json or CONNECTOR_FABRIC_API_KEY env |
Re-install through the admin UI OR set the env var |
401 unauthorized during sync |
Key revoked or invalid | Rotate at https://developers.fabric.so and re-install |
403 forbidden |
Developer API key without workspace-id header | Set CONNECTOR_FABRIC_WORKSPACE_ID or pass workspace_id in config_json |
Sync truncates with maxIterations warning |
Workspace has >10 000 notes (200 pages × 50 limit) | Raise the cap in a future release or trigger another sync |
| OAuth install hangs | oauth_enabled=true but Fabric hasn't shipped OAuth GA |
Set CONNECTOR_FABRIC_OAUTH_ENABLED=false until upstream GA |
| Deletions not appearing | Fabric API doesn't yet surface deleted-state on list endpoints | Run a periodic full sync (re-ingest detects orphans the host's prune job then sweeps) |
- OAuth2 surface activation — flip
oauth_enabledto default true when fabric.so ships OAuth2 GA upstream. - Deletion reconciliation — wire
softDeleteByRemoteId('fabric_note_id', ...)once Fabric exposes a deleted-state on the list endpoint. - Bookmarks / Memories / Spaces — today this connector only walks
/v2/notes. Future versions add the other Fabric resource types behind a config flag.
Apache-2.0 — see LICENSE.
Built and maintained by Padosoft. Part of the AskMyDocs connector ecosystem.