alfred-channel-attachments

star 223

How to read files (audio, documents, images) that Sir sent to Alfred on any channel — Slack file uploads, Telegram voice memos, MMS audio, generic URLs. Converts file references into transcripts + vault records so Alfred doesn't say "I don't see your file".

ssdavidai By ssdavidai schedule Updated 5/20/2026

name: alfred-channel-attachments description: How to read files (audio, documents, images) that Sir sent to Alfred on any channel — Slack file uploads, Telegram voice memos, MMS audio, generic URLs. Converts file references into transcripts + vault records so Alfred doesn't say "I don't see your file". triggers: file, attachment, audio, voice memo, voice note, recording, transcribe, slack file, telegram voice, photo, image, document, pdf, uploaded

Reading Attachments From Any Channel

Sir sends files to Alfred across several channels — Slack uploads, Telegram voice memos, SMS/MMS media, email attachments, and direct drops on the dashboard. Every one of those files gets bytes into the vault; your job is to fetch them inline whenever the conversation references an uploaded file, so you can actually respond to what's inside them.

If you ever catch yourself saying "I don't see the file you uploaded" — you forgot this skill. Call the endpoint.

The one endpoint

self({
  endpoint: "/api/v1/channels/attachment/fetch",
  method: "POST",
  body: {
    source: "slack" | "telegram" | "mms" | "url",
    file_ref: "<channel-specific id>",   // for slack/telegram
    file_url: "<direct url>",            // for mms/url
    file_name: "<optional hint>",        // optional
    mime_type: "<optional hint>"         // optional
  }
})

Returns:

{
  "ok": true,
  "source": "slack",
  "file_name": "voice-memo-2026-04-23.m4a",
  "mime_type": "audio/m4a",
  "size": 482317,
  "vault_path": "inbox/voice-memo-2026-04-23.m4a",
  "transcript": "Hey Alfred, I wanted to follow up on the Erste meeting...",
  "text": "(same as transcript, or text content for docs)"
}

You get:

  • transcript — ready-to-use transcript for audio (Whisper via Groq, ~3s round trip).
  • text — inline content for text documents (up to 30KB).
  • vault_path — where it lives. The async MediaIngestionWorkflow will build a full vault record too (so search + surveyor linking pick it up later), but you don't have to wait.

When to call it

  • Sir's message says "here's the recording" or "I just sent you audio" or "take a look at this PDF"
  • Slack message shows a file_share event or your session context mentions files[]
  • Telegram message shows a voice memo icon or voice/audio in context
  • Twilio SMS payload includes MediaUrl0
  • Someone pastes a raw URL to a file (e.g. Dropbox, Google Drive public link, pre-signed S3)

Always call it before replying. Even if you're not sure — err on the side of fetching. It's cheap.

Per-channel specifics

Slack

self({ endpoint: "/api/v1/channels/attachment/fetch", method: "POST",
  body: { source: "slack", file_ref: "F0ABC123" } })

file_ref is Slack's file ID (starts with F). If your session context has files[].id, use that. Downloads via the Slack Composio OAuth credential — no extra auth needed from you.

Telegram

self({ endpoint: "/api/v1/channels/attachment/fetch", method: "POST",
  body: { source: "telegram", file_ref: "<file_id>" } })

Telegram's file_id is a long opaque string like AAQB.... Works for voice memos (voice.file_id), audio files (audio.file_id), documents (document.file_id), photos (photo[-1].file_id = largest).

MMS (Twilio)

self({ endpoint: "/api/v1/channels/attachment/fetch", method: "POST",
  body: { source: "mms", file_url: "<MediaUrl0 from Twilio>" } })

Generic URL

self({ endpoint: "/api/v1/channels/attachment/fetch", method: "POST",
  body: { source: "url", file_url: "https://..." } })

Use when Sir pastes a pre-signed URL or a public Dropbox/Drive link.

Don't double-handle email

Email attachments have their own endpoint — alfred-email-channel/SKILL.md already covers that flow using /api/v1/email/attachment/<message_id>/<attachment_id>. Don't route email attachments through this skill.

What happens async

Every call emits a stream_type: media event to system-media-ingestion.jsonl. The MediaIngestionWorkflow will:

  • Build a permanent vault record for the file (so search can find it tomorrow)
  • Run the full clerk enrichment pass on the content (entities, topic_tags, related_matters)
  • Let the surveyor embed + structurally link it next tick

You don't need to wait for this. You already have the content from the endpoint's synchronous response. But it means asking "find the transcript of the voice memo Sir sent yesterday" works later even if you didn't save it explicitly.

Error handling

If the endpoint returns ok: false:

  • resolve failed — bad file_ref or the channel's connected account is broken. Tell Sir the file ref wasn't resolvable; don't pretend you read it.
  • download failed — network issue or auth expired. Try once more; if it fails again, tell Sir.
  • GROQ_API_KEY not set — will just skip transcription silently and return the file_name + vault_path. You can still tell Sir the file was saved, but you don't have the content to discuss.

Never invent content. If you didn't get a transcript, don't pretend you did.

Install via CLI
npx skills add https://github.com/ssdavidai/alfred --skill alfred-channel-attachments
Repository Details
star Stars 223
call_split Forks 28
navigation Branch main
article Path SKILL.md
More from Creator