Back the ResourceManager with the local filesystem, S3, or a GitHub repository.
A storage provider is where stored content
lives: templates, uploaded files, and anything the ResourceManager reads or
writes. One provider is active per server, named by storage_module in the
manifest.
Provider
Package
Backing store
When to pick it
local
tai42-storage-local
A directory on the server’s own disk.
A single-process install.
s3
tai42-storage-s3
Any S3-compatible bucket, including MinIO.
A multi-replica fleet, or durable shared object storage.
github
tai42-storage-github
A branch of a GitHub repository.
Every write should be a reviewable commit.
Local storage is per-process state on one machine’s disk. A multi-replica fleet
gives each replica its own copy — use S3 or GitHub instead.
Each provider’s package, its storage_module manifest key, its STORAGE_<KIND>_*
settings, and its store-specific setup (S3 bucket policy and MinIO addressing,
GitHub token scopes and the 1 MiB / CDN-staleness limits) live on the plugin
page:
storage-local
STORAGE_LOCAL_* — a root directory on local disk, required: every call refuses until it is set.
storage-s3
STORAGE_S3_*, the bucket policy, and MinIO.
storage-github
STORAGE_GITHUB_*, token scopes, and the write/read caveats.
When a participant sends a file over the conversation
bridge — a photo, document, voice or audio clip,
or video — the platform fetches the bytes, verifies them, and stores them by
reference through the active storage provider, then serves them back from a
same-origin capability URL that carries an unguessable id. Ingestion therefore
needs a registered storage provider (any of the three above). The default
self-hosted image bakes and selects storage-local, so inbound media works out
of the box; register no provider and an inbound file is rejected loudly — the
sender is told “That attachment could not be received.” (or the route’s
reply_texts.rejected_could_not_receive) — rather than dropped in silence.Per-kind size ceilings are MEDIA_INGEST_* settings —
MEDIA_INGEST_MAX_IMAGE_BYTES (8 MiB), MEDIA_INGEST_MAX_AUDIO_BYTES (16 MiB),
MEDIA_INGEST_MAX_VIDEO_BYTES (25 MiB), and MEDIA_INGEST_MAX_DOCUMENT_BYTES
(25 MiB) by default; the settings reference carries every
MEDIA_INGEST_* variable and its value. Which files are accepted depends on their
kind: photos, audio, and video are stored only when their bytes carry a recognised
signature that matches an allowlisted type — a file that merely claims to be an
image is rejected — while documents of text-like allowlisted types (such as plain
text or CSV) are accepted by their declared type and are always served as a
download, never as active content. Active content such as SVG, HTML, or JavaScript
is on no allowlist and is never accepted.A stored inbound file is retained for the life of its conversation record (30 days
by default): the platform records each file’s expiry in a durable index and a
background reaper walks that index to delete past-horizon files, so nothing is
held forever — a file that outlives its own record is still reaped.Inbound media is stored under the inbound-media/ prefix, which the platform marks
not backed up and unlisted. A backup export leaves
it out and a restore refuses an entry under it. It shows in no listing — not the Studio
Storage screen, not the Studio pickers, not tai storage list or
tai templates list — yet each file is still read, downloaded and deleted by its id.A plugin marks a prefix of its own the same way, under either mark or both, with
tai42_app.storage.mark_not_backed_up(prefix) and tai42_app.storage.mark_unlisted(prefix).
The prefix is a canonical store key followed by / (such as inbound-media/); any other
value raises ValueError. Store keys are canonical at every door, so a key is under a
prefix exactly when it starts with it. A mark lasts one serving epoch: declare it from a
startup handler, which runs at boot and again at every reload.
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"TAI42","description":"tai is an open-source runtime for MCP tools, agents, and workflows — the server that hosts tools, agents, extensions, connectors, hooks, and storage for the TAI42 ecosystem.","colors":{"primary":"#DC143C","light":"#F4718A","dark":"#A01030"},"logo":{"light":"https://mintcdn.com/tai42/8zNeABFQpXRG0k_n/logo/light.png?fit=max\u0026auto=format\u0026n=8zNeABFQpXRG0k_n\u0026q=85\u0026s=2140f77615492c689d62fcb3a5df2d31","dark":"https://mintcdn.com/tai42/8zNeABFQpXRG0k_n/logo/dark.png?fit=max\u0026auto=format\u0026n=8zNeABFQpXRG0k_n\u0026q=85\u0026s=22db5fbcb0ff42b44dd8057f0edbb842"},"favicon":{"light":"https://mintcdn.com/tai42/8zNeABFQpXRG0k_n/logo/icon.png?fit=max\u0026auto=format\u0026n=8zNeABFQpXRG0k_n\u0026q=85\u0026s=93b0ca22f7b4a2c0a6a18f49aedbfd73","dark":"https://mintcdn.com/tai42/6-OGKPd0gfVyDs4N/logo/icon-dark.png?fit=max\u0026auto=format\u0026n=6-OGKPd0gfVyDs4N\u0026q=85\u0026s=e1630da05506747fe41cf300761cf3cf"},"appearance":{"default":"light"},"navbar":{"links":[{"icon":"github","href":"https://github.com/tai42ai/tai42","label":"GitHub"}],"primary":{"type":"button","label":"Get started","href":"/getting-started/installation"}},"footer":{"socials":{"github":"https://github.com/tai42ai","website":"https://tai42.ai"},"links":[{"header":"Project","items":[{"label":"Contributing","href":"/contributing"}]}]},"search":{"prompt":"Search the TAI42 docs"},"seo":{"metatags":{"og:title":"TAI42 — the OS for AI tools","og:description":"An open-source runtime for MCP tools, agents, and workflows.","og:image":"/images/og-image.svg","og:type":"website","twitter:card":"summary_large_image","twitter:title":"TAI42 — the OS for AI tools","twitter:image":"/images/og-image.svg"},"indexing":"navigable"},"fonts":{"heading":{"family":"Geist"},"body":{"family":"Inter"}},"contextual":{"options":["copy","view","chatgpt","claude"],"display":"header"},"styling":{"latex":true},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"tai42","hasAudioNarration":false,"actualSubdomain":"tai42","customDomains":["docs.tai42.ai"],"gitSource":{"type":"github","owner":"tai42ai","repo":"tai-docs","deployBranch":"main","contentDirectory":"","isPrivate":false,"mountPath":"","label":""},"chroma":{"collectionId":"70c7974a-74c7-4ee5-8636-97a098b8bbe6","liveDeploymentHistoryId":"6aeca718754501e0c6b68d06","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6aeca718754501e0c6b68d06"},"entitlements":{"AI_CHAT":{"status":"DISABLED"}},"buildId":"6aecafc07e5e99a1eb7058ad","clientVersion":"0.0.4071","searchFilterCounts":[{"language":"default","tag":"Reference","count":356},{"language":"default","tag":"HTTP API","count":260},{"language":"default","tag":"Docs","count":124},{"language":"default","tag":"CLI","count":46},{"language":"default","tag":"Python SDK","count":38},{"language":"default","tag":"Concepts","count":35},{"language":"default","tag":"access-control","count":35},{"language":"default","tag":"states","count":33},{"language":"default","tag":"Plugins","count":30},{"language":"default","tag":"conversations","count":22}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[],"googleFontsInlined":true},"customCss":[],"page":{"pagePath":"operate/storage","slug":"/operate/storage","pageMetadata":{"title":"Storage providers","description":"Back the ResourceManager with the local filesystem, S3, or a GitHub repository.","icon":"database","href":"/operate/storage"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Back the ResourceManager with the local filesystem, S3, or a GitHub repository.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,li:`li`,p:`p`,strong:`strong`,tbody:`tbody`,td:`td`,th:`th`,thead:`thead`,tr:`tr`,ul:`ul`,..._provideComponents(),...props.components},{Card,CardGroup,Heading,Table,Warning}=_components;if(!Card)_missingMdxReference(`Card`,true);if(!CardGroup)_missingMdxReference(`CardGroup`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Table)_missingMdxReference(`Table`,true);if(!Warning)_missingMdxReference(`Warning`,true);return _jsxs(_Fragment,{children:[_jsxs(_components.p,{children:[`A storage provider is where `,_jsx(_components.a,{href:`/concepts/storage-and-resources`,children:`stored content`}),`\nlives: templates, uploaded files, and anything the ResourceManager reads or\nwrites. One provider is active per server, named by `,_jsx(_components.code,{children:`storage_module`}),` in the\nmanifest.`]}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Provider`}),_jsx(_components.th,{children:`Package`}),_jsx(_components.th,{children:`Backing store`}),_jsx(_components.th,{children:`When to pick it`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`local`}),_jsx(_components.td,{children:_jsx(_components.code,{children:`tai42-storage-local`})}),_jsx(_components.td,{children:`A directory on the server’s own disk.`}),_jsx(_components.td,{children:`A single-process install.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`s3`}),_jsx(_components.td,{children:_jsx(_components.code,{children:`tai42-storage-s3`})}),_jsx(_components.td,{children:`Any S3-compatible bucket, including MinIO.`}),_jsx(_components.td,{children:`A multi-replica fleet, or durable shared object storage.`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`github`}),_jsx(_components.td,{children:_jsx(_components.code,{children:`tai42-storage-github`})}),_jsx(_components.td,{children:`A branch of a GitHub repository.`}),_jsx(_components.td,{children:`Every write should be a reviewable commit.`})]})]})]}),`\n`,_jsx(Warning,{children:_jsx(_components.p,{children:`Local storage is per-process state on one machine’s disk. A multi-replica fleet\ngives each replica its own copy — use S3 or GitHub instead.`})}),`\n`,_jsx(Heading,{level:`2`,id:`install-and-configure-one`,children:`Install and configure one`}),`\n`,_jsxs(_components.p,{children:[`Each provider’s package, its `,_jsx(_components.code,{children:`storage_module`}),` manifest key, its `,_jsx(_components.code,{children:`STORAGE_\u003cKIND>_*`}),`\nsettings, and its store-specific setup (S3 bucket policy and MinIO addressing,\nGitHub token scopes and the 1 MiB / CDN-staleness limits) live on the plugin\npage:`]}),`\n`,_jsxs(CardGroup,{cols:3,children:[_jsx(Card,{title:`storage-local`,icon:`folder`,href:`/plugins/tai42/storage-local`,children:_jsxs(_components.p,{children:[_jsx(_components.code,{children:`STORAGE_LOCAL_*`}),` — a root directory on local disk, required: every call refuses until it is set.`]})}),_jsx(Card,{title:`storage-s3`,icon:`aws`,href:`/plugins/tai42/storage-s3`,children:_jsxs(_components.p,{children:[_jsx(_components.code,{children:`STORAGE_S3_*`}),`, the bucket policy, and MinIO.`]})}),_jsx(Card,{title:`storage-github`,icon:`github`,href:`/plugins/tai42/storage-github`,children:_jsxs(_components.p,{children:[_jsx(_components.code,{children:`STORAGE_GITHUB_*`}),`, token scopes, and the write/read caveats.`]})})]}),`\n`,_jsx(Heading,{level:`2`,id:`inbound-media`,children:`Inbound media`}),`\n`,_jsxs(_components.p,{children:[`When a participant sends a file over the `,_jsx(_components.a,{href:`/reference/conversation-bridge`,children:`conversation\nbridge`}),` — a photo, document, voice or audio clip,\nor video — the platform fetches the bytes, verifies them, and stores them by\nreference through the active storage provider, then serves them back from a\nsame-origin capability URL that carries an unguessable id. Ingestion therefore\nneeds a registered storage provider (any of the three above). The default\nself-hosted image bakes and selects `,_jsx(_components.code,{children:`storage-local`}),`, so inbound media works out\nof the box; register no provider and an inbound file is rejected loudly — the\nsender is told “That attachment could not be received.” (or the route’s\n`,_jsx(_components.code,{children:`reply_texts.rejected_could_not_receive`}),`) — rather than dropped in silence.`]}),`\n`,_jsxs(_components.p,{children:[`Per-kind size ceilings are `,_jsx(_components.code,{children:`MEDIA_INGEST_*`}),` settings —\n`,_jsx(_components.code,{children:`MEDIA_INGEST_MAX_IMAGE_BYTES`}),` (8 MiB), `,_jsx(_components.code,{children:`MEDIA_INGEST_MAX_AUDIO_BYTES`}),` (16 MiB),\n`,_jsx(_components.code,{children:`MEDIA_INGEST_MAX_VIDEO_BYTES`}),` (25 MiB), and `,_jsx(_components.code,{children:`MEDIA_INGEST_MAX_DOCUMENT_BYTES`}),`\n(25 MiB) by default; the `,_jsx(_components.a,{href:`/reference/settings`,children:`settings reference`}),` carries every\n`,_jsx(_components.code,{children:`MEDIA_INGEST_*`}),` variable and its value. Which files are accepted depends on their\nkind: photos, audio, and video are stored only when their bytes carry a recognised\nsignature that matches an allowlisted type — a file that merely claims to be an\nimage is rejected — while documents of text-like allowlisted types (such as plain\ntext or CSV) are accepted by their declared type and are always served as a\ndownload, never as active content. Active content such as SVG, HTML, or JavaScript\nis on no allowlist and is never accepted.`]}),`\n`,_jsx(_components.p,{children:`A stored inbound file is retained for the life of its conversation record (30 days\nby default): the platform records each file’s expiry in a durable index and a\nbackground reaper walks that index to delete past-horizon files, so nothing is\nheld forever — a file that outlives its own record is still reaped.`}),`\n`,_jsxs(_components.p,{children:[`Inbound media is stored under the `,_jsx(_components.code,{children:`inbound-media/`}),` prefix, which the platform marks\n`,_jsx(_components.strong,{children:`not backed up`}),` and `,_jsx(_components.strong,{children:`unlisted`}),`. A `,_jsx(_components.a,{href:`/operate/backup-and-restore`,children:`backup`}),` export leaves\nit out and a restore refuses an entry under it. It shows in no listing — not the Studio\nStorage screen, not the Studio pickers, not `,_jsx(_components.code,{children:`tai storage list`}),` or\n`,_jsx(_components.code,{children:`tai templates list`}),` — yet each file is still read, downloaded and deleted by its id.`]}),`\n`,_jsxs(_components.p,{children:[`A plugin marks a prefix of its own the same way, under either mark or both, with\n`,_jsx(_components.code,{children:`tai42_app.storage.mark_not_backed_up(prefix)`}),` and `,_jsx(_components.code,{children:`tai42_app.storage.mark_unlisted(prefix)`}),`.\nThe prefix is a canonical store key followed by `,_jsx(_components.code,{children:`/`}),` (such as `,_jsx(_components.code,{children:`inbound-media/`}),`); any other\nvalue raises `,_jsx(_components.code,{children:`ValueError`}),`. Store keys are canonical at every door, so a key is under a\nprefix exactly when it starts with it. A mark lasts one serving epoch: declare it from a\nstartup handler, which runs at boot and again at every reload.`]}),`\n`,_jsx(Heading,{level:`2`,id:`see-also`,children:`See also`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`/concepts/storage-and-resources`,children:`Storage and resources`}),` — the ResourceManager contract.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`/guides/manage-stored-content`,children:`Manage stored content`}),` — the day-to-day commands.`]}),`\n`]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Storage providers","description":"Back the ResourceManager with the local filesystem, S3, or a GitHub repository.","icon":"database","href":"/operate/storage"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Install and configure one","slug":"install-and-configure-one","depth":2,"children":[]},{"title":"Inbound media","slug":"inbound-media","depth":2,"children":[]},{"title":"See also","slug":"see-also","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":[],"subdomain":"tai42","siteName":"TAI42","title":"TAI42 — the OS for AI tools","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-10-26T03:35:03.569Z","originalFileLocation":"operate/storage.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"light\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Back the ResourceManager with the local filesystem, S3, or a GitHub repository.\">\u003cmeta data-mint-head name=\"application-name\" content=\"TAI42\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/tai42/Czx60dmBXmcmJLcB/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/tai42/Czx60dmBXmcmJLcB/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/tai42/Czx60dmBXmcmJLcB/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/tai42/Czx60dmBXmcmJLcB/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/tai42/Czx60dmBXmcmJLcB/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/tai42/Czx60dmBXmcmJLcB/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/tai42/Czx60dmBXmcmJLcB/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/tai42/Czx60dmBXmcmJLcB/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/tai42/Czx60dmBXmcmJLcB/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"TAI42 — the OS for AI tools\">\u003cmeta data-mint-head property=\"og:description\" content=\"An open-source runtime for MCP tools, agents, and workflows.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"TAI42\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.tai42.ai/operate/storage\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://tai42.mintlify.app/images/og-image.svg\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"TAI42 — the OS for AI tools\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"An open-source runtime for MCP tools, agents, and workflows.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://tai42.mintlify.app/images/og-image.svg\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/tai42/Czx60dmBXmcmJLcB/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"TAI42\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#DC143C\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.tai42.ai/operate/storage\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/operate/storage.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.tai42.ai/#organization\",\"name\":\"TAI42\",\"url\":\"https://docs.tai42.ai\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/tai42/8zNeABFQpXRG0k_n/logo/light.png?fit=max\u0026auto=format\u0026n=8zNeABFQpXRG0k_n\u0026q=85\u0026s=2140f77615492c689d62fcb3a5df2d31\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.tai42.ai#website\",\"name\":\"TAI42\",\"url\":\"https://docs.tai42.ai\",\"publisher\":{\"@id\":\"https://docs.tai42.ai/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.tai42.ai/operate/storage#webpage\",\"url\":\"https://docs.tai42.ai/operate/storage\",\"name\":\"Storage providers\",\"description\":\"Back the ResourceManager with the local filesystem, S3, or a GitHub repository.\",\"dateModified\":\"2026-10-26T03:35:03.569Z\",\"isPartOf\":{\"@id\":\"https://docs.tai42.ai#website\"},\"breadcrumb\":{\"@id\":\"https://docs.tai42.ai/operate/storage#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.tai42.ai/operate/storage#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Operate\",\"item\":\"https://docs.tai42.ai/operate/index\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Plugin setup\",\"item\":\"https://docs.tai42.ai/operate/backends\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Storage providers\",\"item\":\"https://docs.tai42.ai/operate/storage\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.tai42.ai/operate/storage#article\",\"headline\":\"Storage providers\",\"name\":\"Storage providers\",\"description\":\"Back the ResourceManager with the local filesystem, S3, or a GitHub repository.\",\"url\":\"https://docs.tai42.ai/operate/storage\",\"mainEntityOfPage\":{\"@id\":\"https://docs.tai42.ai/operate/storage#webpage\"},\"image\":\"https://docs.tai42.ai/images/og-image.svg\",\"dateModified\":\"2026-10-26T03:35:03.569Z\",\"publisher\":{\"@id\":\"https://docs.tai42.ai/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.tai42.ai#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"TAI42\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"TAI42","nav":{"global":null,"tabs":[{"tab":"Docs","groups":[{"group":"Get started","icon":"rocket","pages":[{"title":"TAI42 — the OS for AI tools","sidebarTitle":"Welcome","icon":"house","mode":"wide","href":""},{"title":"Installation","icon":"download","href":"/getting-started/installation"},{"title":"Quickstart","icon":"rocket","href":"/getting-started/quickstart"},{"title":"Mental model","icon":"brain","href":"/getting-started/mental-model"}]},{"group":"Concepts","icon":"lightbulb","pages":[{"title":"Concepts","icon":"compass","href":"/concepts/index"},{"group":"Foundations","icon":"sitemap","pages":[{"title":"The layering","icon":"sitemap","href":"/concepts/layering"},{"title":"The manifest","icon":"scroll","href":"/concepts/manifest"},{"title":"Tools and extensions","icon":"wrench","href":"/concepts/tools-and-extensions"},{"title":"Presets","icon":"layer-group","href":"/concepts/presets"},{"title":"Tool organization","icon":"folder-tree","href":"/concepts/tool-organization"}]},{"group":"Agents","icon":"robot","pages":[{"title":"Agents","icon":"robot","href":"/concepts/agents"},{"title":"Deep agents","icon":"diagram-project","href":"/concepts/deep-agents"},{"title":"Classifiers","icon":"scale-balanced","href":"/concepts/classifiers"},{"title":"Client conversations","icon":"comments","href":"/concepts/client-conversations"}]},{"group":"Around the tool","icon":"wrench","pages":[{"title":"Interactions","icon":"comments","href":"/concepts/interactions"},{"title":"Asking the caller","icon":"reply","href":"/concepts/asking-the-caller"},{"title":"Notifications","icon":"bell","href":"/concepts/notifications"},{"title":"Connectors","icon":"plug","href":"/concepts/connectors"},{"title":"Hooks","icon":"anchor","href":"/concepts/hooks"},{"title":"Triggers and webhook verifiers","icon":"bolt","href":"/concepts/triggers-and-webhooks"},{"title":"Storage and resources","icon":"database","href":"/concepts/storage-and-resources"},{"title":"Backends","icon":"server","href":"/concepts/backends"},{"title":"Sandbox","icon":"box","href":"/concepts/sandbox"}]},{"group":"Platform surfaces","icon":"shield-halved","pages":[{"title":"Access control","icon":"shield-halved","href":"/concepts/access-control"},{"title":"Accounts","icon":"user-lock","href":"/concepts/accounts"},{"title":"Member actions","icon":"user-gear","href":"/concepts/member-actions"},{"title":"User types and permissions","icon":"user-shield","href":"/concepts/permissions"},{"title":"Owned keys","icon":"share-nodes","href":"/concepts/owned-keys"},{"title":"Config and secrets","icon":"key","href":"/concepts/config-and-secrets"},{"title":"Secret values","icon":"user-secret","href":"/concepts/secret-values"},{"title":"Transports","icon":"network-wired","href":"/concepts/transports"},{"title":"Private tool sets","icon":"box","href":"/concepts/private-tool-sets"},{"title":"The MCP-citizen surface","icon":"diagram-project","href":"/concepts/mcp-citizen-surface"},{"title":"The versioning spine","icon":"code-branch","href":"/concepts/versioning-spine"},{"title":"Live operations","icon":"gauge-high","href":"/concepts/live-operations"},{"title":"The worker bus","icon":"tower-broadcast","href":"/concepts/worker-bus"},{"title":"States","icon":"database","href":"/concepts/states"},{"title":"jq variables","icon":"dollar-sign","href":"/concepts/jq-variables"},{"title":"The marketplace","icon":"store","href":"/concepts/marketplace"}]}]},{"group":"Guides","icon":"map","pages":[{"title":"Guides","icon":"map","href":"/guides/index"},{"group":"Using the OS","icon":"wrench","pages":[{"title":"Build a tool","icon":"wrench","href":"/guides/build-a-tool"},{"title":"Bring an MCP server","icon":"plug","href":"/guides/bring-an-mcp-server"},{"title":"Connect an OAuth provider","icon":"key","href":"/guides/connect-an-oauth-provider"},{"title":"Apply an extension","icon":"puzzle-piece","href":"/guides/apply-an-extension"},{"title":"Create and version a preset","icon":"layer-group","href":"/guides/create-and-version-a-preset"},{"title":"Author an agent","icon":"robot","href":"/guides/author-an-agent"},{"title":"Use the ready-made agents","icon":"wand-magic-sparkles","href":"/guides/use-the-ready-made-agents"},{"title":"Use interactions","icon":"comments","href":"/guides/use-interactions"},{"title":"The standard toolbox","icon":"toolbox","href":"/guides/standard-toolbox"},{"title":"Set up access control","icon":"shield-halved","href":"/guides/access-control"},{"title":"Use owned keys","icon":"share-nodes","href":"/guides/owned-keys"},{"title":"Schedule a tool","icon":"clock","href":"/guides/schedule-a-tool"},{"title":"Fire a tool from a webhook","icon":"bolt","href":"/guides/fire-a-tool-from-a-webhook"},{"title":"WhatsApp to an agent","icon":"whatsapp","href":"/guides/whatsapp-to-agent"},{"title":"Telegram / Slack to an agent","icon":"hashtag","href":"/guides/telegram-slack-to-agent"},{"title":"Link a person across channels","icon":"link","href":"/guides/link-a-person-across-channels"},{"title":"Connect your own system","icon":"webhook","href":"/guides/connect-your-own-system"},{"title":"One bot, many skills","icon":"sitemap","href":"/guides/one-bot-many-skills"},{"title":"Manage stored content and templates","icon":"database","href":"/guides/manage-stored-content"},{"title":"Expose a private tool set","icon":"box","href":"/guides/private-tool-set"}]}]},{"group":"Operate","icon":"server","pages":[{"title":"Operate","icon":"server","href":"/operate/index"},{"group":"Run and operate","icon":"cloud-arrow-up","pages":[{"title":"Deploy","icon":"cloud-arrow-up","href":"/operate/deploy"},{"title":"Infrastructure by feature","icon":"layer-group","href":"/operate/infrastructure"},{"title":"Deploying the Studio","icon":"cloud-arrow-up","href":"/operate/studio"},{"title":"Embed in your own ASGI process","icon":"server","href":"/operate/embed"},{"title":"Manage a fleet","icon":"server","href":"/operate/manage-a-fleet"},{"title":"Observe","icon":"chart-line","href":"/operate/observe"},{"title":"Back up and restore","icon":"floppy-disk","href":"/operate/backup-and-restore"},{"title":"Checkpoints and retention","icon":"clock-rotate-left","href":"/operate/checkpoints"}]},{"group":"Plugin setup","icon":"puzzle-piece","pages":[{"title":"Task backends","icon":"server","href":"/operate/backends"},{"title":"Sandbox","description":"Install one sandbox provider — container-isolated or direct-on-host — and wire the engine, durability, and egress.","icon":"box","href":"/operate/sandbox"},{"title":"Storage providers","icon":"database","href":"/operate/storage"},{"title":"Accounts and sign-in","description":"Give humans logins with the Postgres accounts provider.","icon":"user-lock","href":"/operate/accounts"}]}]},{"group":"Self-hosted","icon":"box","pages":[{"title":"Self-hosted","icon":"box","href":"/self-hosted/index"},{"title":"Quickstart","icon":"docker","href":"/self-hosted/quickstart"},{"title":"Web stacks","icon":"window","href":"/self-hosted/web-stacks"},{"title":"Upgrades","icon":"arrow-up-right-dots","href":"/self-hosted/upgrades"},{"title":"Verify artifacts","icon":"shield-check","href":"/self-hosted/verify"},{"title":"Ops notes","icon":"screwdriver-wrench","href":"/self-hosted/ops"}]},{"group":"Marketplace","icon":"store","pages":[{"title":"Marketplace","icon":"store","href":"/marketplace/index"},{"title":"Browse and search","icon":"magnifying-glass","href":"/marketplace/browse"},{"title":"Install a plugin","icon":"download","href":"/marketplace/install"},{"title":"Advisories","icon":"triangle-exclamation","href":"/marketplace/advisories"},{"title":"Author plugin docs","icon":"file-lines","href":"/marketplace/authoring-docs"},{"title":"Publish a connector without code","icon":"file-code","href":"/plugins/authoring-descriptor-plugins"}]},{"group":"Integrations","icon":"plug","pages":[{"title":"Integrations","icon":"plug","href":"/integrations/index"},{"title":"Claude Desktop","icon":"comment","href":"/integrations/claude-desktop"},{"title":"Cursor","icon":"arrow-pointer","href":"/integrations/cursor"},{"title":"MCP clients","icon":"plug","href":"/integrations/mcp-clients"}]},{"group":"Babelfish","icon":"fish","pages":[{"title":"Babelfish","icon":"fish","href":"/babelfish/index"},{"title":"Flows editor","icon":"pen-ruler","href":"/babelfish/studio"},{"title":"The agenda state template","icon":"list-checks","href":"/babelfish/agenda"},{"title":"Visual jq in flows","icon":"diagram-project","href":"/babelfish/jq-editor"},{"title":"Wiring an outcome by hand","icon":"diagram-next","href":"/babelfish/wire-form"}]},{"group":"Plugins","icon":"puzzle-piece","pages":[{"title":"Plugins","icon":"puzzle-piece","href":"/plugins/index"},{"group":"Tools","icon":"wrench","pages":[{"title":"toolbox","href":"/plugins/tai42/toolbox"},{"title":"tools-github","href":"/plugins/tai42/tools-github"},{"title":"tools-stripe","href":"/plugins/tai42/tools-stripe"},{"title":"tools-twilio","href":"/plugins/tai42/tools-twilio"},{"title":"tools-whatsapp","href":"/plugins/tai42/tools-whatsapp"}]},{"group":"Identity","icon":"id-card","pages":[{"title":"accounts-postgres","href":"/plugins/tai42/accounts-postgres"},{"title":"identity-redis","href":"/plugins/tai42/identity-redis"}]},{"group":"Agents","icon":"robot","pages":[{"title":"agents","href":"/plugins/tai42/agents"}]},{"group":"Backends","icon":"server","pages":[{"title":"backend-arq","href":"/plugins/tai42/backend-arq"},{"title":"backend-celery","href":"/plugins/tai42/backend-celery"},{"title":"backend-rq","href":"/plugins/tai42/backend-rq"}]},{"group":"Sandboxes","icon":"box","pages":[{"title":"sandbox-docker","href":"/plugins/tai42/sandbox-docker"},{"title":"sandbox-local","href":"/plugins/tai42/sandbox-local"}]},{"group":"Channels","icon":"paper-plane","pages":[{"title":"channel-slack","href":"/plugins/tai42/channel-slack"},{"title":"channel-telegram","href":"/plugins/tai42/channel-telegram"},{"title":"channel-twilio","href":"/plugins/tai42/channel-twilio"},{"title":"channel-web","href":"/plugins/tai42/channel-web"},{"title":"channel-whatsapp","href":"/plugins/tai42/channel-whatsapp"}]},{"group":"Monitoring","icon":"chart-line","pages":[{"title":"monitoring-langfuse","href":"/plugins/tai42/monitoring-langfuse"}]},{"group":"Storage","icon":"database","pages":[{"title":"storage-github","href":"/plugins/tai42/storage-github"},{"title":"storage-local","href":"/plugins/tai42/storage-local"},{"title":"storage-s3","href":"/plugins/tai42/storage-s3"}]},{"group":"Webhook verifiers","icon":"bolt","pages":[{"title":"webhook-verifier-github","href":"/plugins/tai42/webhook-verifier-github"},{"title":"webhook-verifier-stripe","href":"/plugins/tai42/webhook-verifier-stripe"}]},{"group":"Connect outside systems","icon":"plug","pages":[{"title":"Atlassian","href":"/plugins/tai42/connector-atlassian"},{"title":"GitHub","href":"/plugins/tai42/connector-github"},{"title":"Google","href":"/plugins/tai42/connector-google"},{"title":"Slack","href":"/plugins/tai42/connector-slack"},{"title":"mcp-dynamic-postgres","href":"/plugins/tai42/mcp-dynamic-postgres"}]}]}]},{"tab":"Studio","pages":[{"title":"Studio","href":"/studio"}]},{"tab":"Reference","pages":[{"title":"Reference","href":"/reference/api"}]}]},"basePath":"","title":"TAI42 — the OS for AI tools","buildId":"dpl_GZsjphRpnhWkstV12jxWNcMHFyox","deploymentId":"dpl_GZsjphRpnhWkstV12jxWNcMHFyox","dynamics":[],"chunks":[]}