Files, attachments and embeds
Work is not just text. You attach the design file, the spreadsheet, the screenshot that explains the bug. Elliptic gives you two ways to bring outside content into your workspace: file attachments, which upload a real file into your organization's private storage, and link embeds, which turn a pasted URL into a playable video, an interactive frame, or a rich preview card. Both are org-scoped, both keep their context, and both are available to your agents on the same surfaces, since agents operate Elliptic the same way your team does.
This page covers uploading files, attaching them to the things you work on, and embedding external links. Where it matters, it explains exactly what happens behind the scenes so you can reason about size limits, link lifetimes, and how self-hosted air-gapped mode changes embed behavior.
Uploading files
When you attach a file in Elliptic, the file does not pass through the application server. It goes straight from your browser to object storage over a temporary, signed URL. This keeps uploads fast and keeps large files off the API. The flow has three parts: reserve, upload, and confirm.
- ReserveYour browser calls
presign-uploadwith the filename, content type, and the file size in bytes. The server validates that the content type is allowed and that the claimed size is within the limit, reserves aStoredObjectrecord for the file, and hands back a presigned PUT URL valid for 15 minutes. The object is marked not-yet-uploaded at this point, withis_uploadedset to false. - UploadYour browser sends the file directly to storage with a single
PUTto that presigned URL, using the same content type. The bytes never touch the Elliptic API. If the PUT fails, nothing is attached and the reserved record stays not-yet-uploaded. - ConfirmYour browser calls
confirmon the object. The server checks that the file actually landed in storage, reads back its real size, and re-validates the size limit server-side. If the landed file is over the limit it is deleted from storage and the upload is rejected. On success the object's true size and ETag are recorded andis_uploadedflips to true, which is what makes it downloadable and listable.
confirm reads the object's real size back from storage and enforces the limit again. A file is never considered attached until it passes this server-side re-check.Size and type limits
Uploads are size- and type-limited. The default maximum file size is 25 MB. The size limit is enforced in three places: the web client checks it before starting an upload and shows a clear error, the server checks the claimed size at reserve time, and the server re-checks the real size at confirm time.
Only an allowlist of content types may be uploaded. Out of the box, the allowed types are:
- Images: PNG, JPEG, GIF, WebP, and SVG.
- Documents: PDF, plain text, CSV, Markdown, and JSON.
- Office files: Word (
.docand.docx), Excel (.xlsx), and PowerPoint (.pptx). - Archives: ZIP.
Anything uploaded with an image/* content type is recorded as an image, and everything else is recorded as a file. That distinction is what lets the interface show images as thumbnails and other files as document rows. A content type that is not on the allowlist is rejected at reserve time, before any upload begins.
file_size_limit_bytes and allowed_upload_content_types). On the hosted instance at elliptic.sh they are the defaults above. If you self-host, you can adjust both in your API configuration. File storage must also be configured: if your instance has no object storage set up, uploads fail with "Object storage is not configured" and attachment features stay off.Attaching anywhere
Every uploaded file belongs to your organization and is bound to one thing it is attached to. Elliptic uses a single polymorphic attachment model, so the same upload mechanism works across the product. A file can be attached to a:
- Comment, so feedback can carry a screenshot or a document.
- Note, alongside the embeds in the note's attachment panel.
- Task, to keep a spec or asset next to the work.
- Project, for files that belong to the whole workstream.
- AI chat, so a conversation with your company brain can reference a file.
- General, when a file is not tied to anything in particular yet.
Attachments are always scoped to your organization. A file uploaded in one org is never visible from another, and every list, download, and delete is checked against the org you are in.
Attaching on a note
Notes have a dedicated side panel for attachments and embeds. Use Add in the Attachments section to pick a file from your machine. It uploads with the three-step flow above, bound directly to the note, and appears in the attachment list when it finishes. The note panel enforces the same 25 MB limit on the client and shows a toast if you pick something larger.
Attaching on a comment
Comments attach files by binding already-uploaded objects. You upload first, which gives you object IDs, then you create the comment with those IDs in its attachment_ids. When the comment is created, Elliptic binds those objects to it. Binding only succeeds for objects you uploaded yourself, in the same org, that have finished uploading. This two-step pattern, upload then bind, is what lets you stage attachments before the comment exists.
Downloading
Files are private. You never get a permanent public link to them. Instead, when you open or download an attachment, Elliptic mints a fresh short-lived presigned download link that points straight at storage and expires in 5 minutes. Opening the same file later mints a new link. A download is only possible once the file has finished uploading, so a half-finished upload cannot be fetched.
Deleting
Deleting an attachment removes both the stored file and its record. The object is deleted from storage and the database row is removed, so it stops appearing in lists and can no longer be downloaded. Deletion is a member-level action, the same level required to upload.
Rich link embeds
Not everything needs to be uploaded. A lot of your context already lives at a URL: a Loom walkthrough, a Figma frame, a Google Doc, a GitHub pull request. Elliptic turns a pasted link into one of two things, depending on the provider: an iframe you can watch or interact with inline, or a link card with a title, description, and thumbnail.
Players and cards
Some providers are recognized by their URL pattern and rendered in an iframe. These are:
| Provider | Renders as | From a URL like |
|---|---|---|
| YouTube | Inline video player | youtube.com/watch?v=… or youtu.be/… |
| Loom | Inline video player | loom.com/share/… or loom.com/embed/… |
| Vimeo | Inline video player | vimeo.com/… |
| Figma | Inline interactive frame | figma.com/file/…, /design/…, or /proto/… |
Other providers are rendered as a link card rather than an iframe. Elliptic recognizes Google Docs (docs.google.com), Notion (notion.so), Airtable (airtable.com), and GitHub (github.com) by their host, and any other http or https URL is treated as a generic link. For these, Elliptic fetches the page and reads its Open Graph tags to build the card: the og:title, og:description, and og:image become the card's title, description, and thumbnail. If a page has no Open Graph title, Elliptic falls back to its plain HTML <title>. When no preview metadata can be found, the card simply shows the provider name and a link out.
Preview without saving
Before you commit an embed, you can preview what it will look like. The unfurl step resolves a URL's embed metadata, the provider, whether it is an iframe or a card, the iframe URL or the title, description, and thumbnail, without persisting anything. This is what powers the live preview as you paste. Only http and https URLs can be embedded, anything else is rejected. The page fetch during unfurl uses a short timeout, and if the fetch fails for any reason, the embed still resolves to a plain link card rather than erroring out.
Persisted note embeds
Notes can hold saved embeds. Paste a link into the Embeds section of a note's side panel and press Enter or Add, and Elliptic unfurls the URL and stores the result as a note embed with its metadata. Iframes render inline in a video-shaped frame, cards render with their thumbnail, title, and description and a link out to the original. The metadata is cached on the embed when it is created, so the note keeps showing the preview without re-fetching every time you open it. Remove an embed with the trash control on its card.
- Open the note panelIn a note, find the Embeds section in the right-hand attachment panel.
- Paste a linkPaste a YouTube, Figma, Loom, or any other link into the input. A YouTube, Loom, Vimeo, or Figma link becomes an iframe, a Google Doc or GitHub link becomes a card.
- Add itPress Enter or select Add. Elliptic unfurls the link, saves it to the note, and renders it inline.
Air-gapped mode disables outbound fetch
Self-hosted instances can run in a zero-egress air-gapped mode. When air-gapped mode is enabled, Elliptic does not make outbound requests to fetch external pages, so Open Graph unfurling is turned off. In that mode, link cards resolve from the URL alone: you still get the provider and a link out, but there is no fetched title, description, or thumbnail. Iframes are unaffected, because they are built from the URL and never required a fetch in the first place. The hosted instance at elliptic.sh is not air-gapped, so it fetches Open Graph metadata normally.
How it fits together
Attachments and embeds are deliberately different tools. An attachment is a real file you own, stored privately in your org, reached only through short-lived signed links. An embed is a reference to something that lives elsewhere, rendered as an iframe or a card. Reach for an attachment when the artifact should live in Elliptic, and an embed when it already has a home and you just want it visible in context.
- Attachments are size- and type-limited, uploaded directly to storage, confirmed server-side, and downloadable only via 5-minute signed links.
- Embeds are iframes (YouTube, Loom, Vimeo, Figma) or Open Graph cards (Google Docs, Notion, Airtable, GitHub, and any link), previewable before saving and persistable on notes.
- Both are scoped to your organization, and both are surfaces your agents can use the same way your team does.
