Skip to content

AIT-470: Instagram tool surface - #72

Merged
ord669 merged 7 commits into
mainfrom
ait-470-instagram-tool-surface
Aug 24, 2026
Merged

AIT-470: Instagram tool surface#72
ord669 merged 7 commits into
mainfrom
ait-470-instagram-tool-surface

Conversation

@ord669

@ord669 ord669 commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Wraps the Instagram endpoints we hold Advanced access to but never exposed. Four repos, one branch: ait-470-instagram-tool-surface.

MCP tools (backend)

  • list_instagram_media — posts, stories, tagged posts, plus a single post with carousel children. This is where media ids come from, so get_instagram_insights and list_instagram_comments stop being unreachable.
  • list_instagram_mentions — where the account was @mentioned, and the post behind it.
  • list_instagram_conversations — DM threads, one thread's messages, and the profile behind an IGSID.
  • get_instagram_account — profile fields insights never served, plus the publishing quota on request.
  • set_instagram_thread_setup — starter questions and the thread menu.
  • send_message now documents the Instagram payloads it always relayed: quick replies, generic/button templates, sender actions.

CLI: instagram media, instagram mentions, instagram threads, instagram profile.

Docs: new Mentions page; CLI and MCP sections added to Your posts, Inbox, Insights, and Ice breakers.

Skill: integrate-hookmyapp no longer tells agents that listing posts is "raw HTTP; no CLI command".

Ticket: https://linear.app/hookmyapp/issue/AIT-470/instagram-we-expose-about-a-third-of-what-our-approved-permissions

Notes for review:

  • Conversation and participant ids are Meta's opaque thread keys, not numeric Graph ids, so they get a URL-safe-alphabet guard instead of assertIgObjectId.
  • The conversations edge and the messenger_profile write both send platform=instagram; without it a Page-linked account can answer from, or be written to, the Messenger inbox.
  • Page sizes clamp to Meta's 100 ceiling, which otherwise truncates silently and reads as end-of-list.

@coderabbitai

coderabbitai Bot commented Aug 24, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 36 minutes.

View limit details

Limit details: You’ve used all 2 included reviews currently available. Your 84 included PR review attempts over the past 7 days set your current allowance at 2 reviews per hour.

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9a6e16cb-2be9-40ea-a201-c3a42d21aeed

📥 Commits

Reviewing files that changed from the base of the PR and between 4e09b9c and e7f7b19.

📒 Files selected for processing (5)
  • src/commands/__tests__/instagram-content.test.ts
  • src/commands/__tests__/instagram-inbox.test.ts
  • src/commands/instagram-content.ts
  • src/commands/instagram-inbox.ts
  • src/commands/instagram.ts

Comment @coderabbitai help to get the list of available commands.

…e CLI

Mirrors the new MCP tools so the CLI stops sending people to raw curl for
things we are approved for:

- instagram media — posts, stories, and tagged posts; --media reads one post
  and expands carousel children. Until now --media on insights and comments
  wanted an id the CLI never produced, and its own help sourced it "from the
  inbound webhook".
- instagram mentions — where other accounts @mentioned you.
- instagram threads — DM threads, one thread's messages, and the public
  profile behind an IGSID. Scoped with platform=instagram so a linked Page
  cannot answer with the wrong inbox.
- instagram profile — the profile fields insights never served, plus the
  publishing quota behind --quota.

Thread and participant ids are Meta's opaque keys rather than numeric Graph
ids, so they get a URL-safe-alphabet guard instead of the numeric one.
@ord669
ord669 marked this pull request as ready for review August 24, 2026 08:34

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 000a441a4e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +76 to +77
if (rows.length === 0) process.stdout.write('No messages in this thread.\n');
return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Print the cursor when a thread has more messages

When a thread contains more than the default 25 messages, human-readable mode returns here without printing res.paging.cursors.after, unlike the conversation, media, and mentions list paths. As a result, users receive a silently truncated thread and cannot determine the value required by --after unless they rerun the command in JSON mode; print the continuation hint before returning.

Useful? React with 👍 / 👎.

ord669 added 5 commits August 24, 2026 11:54
…hook

Meta documents /{ig-user-id}/mentions as POST-only: it creates the reply. The
list tool this branch added would have failed against Meta on every call.

The real read is a field expansion on the IG-User node —
mentioned_comment.comment_id(<id>) or mentioned_media.media_id(<id>) — keyed
by an id that only the mentions webhook supplies. Replying keys off media_id
in both shapes, so a comment mention needs both ids.

Renamed to get_instagram_mention / `instagram mentions --media|--comment`,
which reads the mention and posts the reply in one call, and rejects a reply
missing media_id locally instead of letting Meta return an unhelpful error.
The docs and skill now say plainly that no listing exists and point at the
webhook.
Meta gates /{ig}/stories and /{ig}/tags on a Facebook User access token plus
pages_read_engagement, and the Instagram-Login page states the setup "cannot
access ads or tagging". Every channel we connect is Instagram Login, so the
stories and tagged sources would have failed for every customer.

Removed rather than left in to fail: an option that never works is worse than
an absent one. list_instagram_media is now posts plus the single-post read.

content_publishing_limit is documented against
instagram_business_content_publish, so get_instagram_account gates on that
scope when the quota is requested and on basic when it is not.

The docs page keeps its stories and tags curl, now under a warning saying who
can actually call them.
…hreads

From the Codex review, verified against Meta docs before applying.

Accepted:
- A conversation has NO /messages edge. Meta serves the messages as a field
  expansion on the conversation node and nests them under messages.data, so
  the old call returned an empty list and dropped the cursor silently.
- mentioned_comment / mentioned_media are Facebook-Login expansions. The
  Instagram-Login Mentions guide documents exactly two calls on
  graph.instagram.com: GET /<IG_ID>/tags to see what tagged or @mentioned you,
  and POST /<IG_ID>/mentions to reply. The tool is now reply-only and the read
  is list_instagram_media with source "tagged".

Rejected, both contradicted by Meta:
- ice_breakers as a flat array. The IG-Login doc shows the call_to_actions
  wrapper, and the Messenger variant marks locale "default" as REQUIRED.
- fields in the DELETE query string. Meta sends it as a JSON body.

Also reverses my own earlier removal of /tags: I had read the IG-User /tags
REFERENCE page, which lists Facebook-Login permissions. The Instagram-Login
guide is the one that applies to us, and it documents /tags on
graph.instagram.com under instagram_business_* scopes. /stories stays out —
no Instagram-Login guide documents it.
Reading a thread printed the messages and stopped. The conversation list
right below it ends with a "More: --after <cursor>" line, so the same
command taught you how to page in one mode and not the other, and --after
was undiscoverable for threads.

The cursor is there, just nested: a conversation has no /messages edge, so
Meta expands the messages onto the node and the cursor lands under
messages.paging.cursors.after rather than at the top level. The JSON output
already read it from there; the human-readable output did not.

Found by a second Codex pass over the branch.
Same defect as the backend tool. --after was sent as a top-level param, so
it paged the conversation node rather than the expanded messages edge, and
the "More: --after" hint added in e7f7b19 pointed at a cursor that returned
the same page.

The modifiers now ride inside the expansion as
messages.limit(N).after(CUR){...}, and the cursor is validated before it is
interpolated there, since a stray ) or { would escape the expansion.
@ord669
ord669 merged commit 5477476 into main Aug 24, 2026
3 checks passed
@ord669
ord669 deleted the ait-470-instagram-tool-surface branch August 24, 2026 10:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant