Download the PHP package ekumanov/flarum-ext-claude-reply without Composer

On this page you can find all versions of the php package ekumanov/flarum-ext-claude-reply. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package flarum-ext-claude-reply

Claude Reply

Mention a designated bot account in a Flarum 2.0 discussion and Claude replies in-thread, as that account.

Built to be kept on a short leash: only explicitly allowed members can trigger a reply, only in explicitly allowed tags, never in private discussions, under both a per-member and a forum-wide daily cap.

How it works

  1. An allow-listed member mentions the bot account (@claude_user by default) in a post.
  2. A listener runs inside the post-save request, checks the gates, writes an audit row, and queues a job. No network I/O happens in the request.
  3. The worker assembles a token-budgeted excerpt of the discussion, makes one Messages API call, and posts the reply through Flarum's own API layer — so mentions resolve, notifications fire, realtime pushes it, and any purge-on-write hooks run exactly as for a human post.

There is no session state. Claude's own replies are ordinary posts, so the next time it is mentioned in the same thread it reads its earlier answers back as context.

Requirements

Setup

1. Bot account. Create a normal user for Claude to post as. It needs reply permission in the allowed tags, and must not be in a group whose posts require approval — otherwise replies land in the approval queue and never appear.

2. API key. Either paste it into the admin field, or — better — put it in config.php:

Resolution order is config.php → ANTHROPIC_API_KEY in the environment → the settings table, and the first one found wins. The admin field exists because not every install has shell access, and it is handled carefully: the value is masked out of the admin page payload, so it is never sent to a browser, and saving the page without touching the field cannot overwrite it. It is still stored in the settings table though, which means it is in your database backups and your settings cache — which config.php values are not. Prefer config.php where you can.

3. Settings (Admin → Extensions → Claude Reply). The gate is fail-closed and does nothing until you configure it:

Setting Default Notes
Enable Claude replies off Master switch
Allowed members / groups empty = nobody Pick from a search box
Allowed tags empty = no tag Pick from your tag list

Enabling the extension alone cannot send a single post to Anthropic; you have to name who and where.

Others worth tuning: model (a dropdown of the models your key can actually call), effort (default medium), context_token_budget (20000), per_user_daily_limit (2), daily_reply_limit (25), persona_prompt, footer.

Who may summon a reply

Six lists, in three pairs — members, groups, tags — each with an allow list and a deny list. They resolve in a fixed order, and the first match decides:

  1. denied members → no
  2. allowed members → yes
  3. denied groups → no
  4. allowed groups → yes
  5. nothing matched → no

Two rules fall out of that, and they are the ones to remember. Deny beats allow within a level, so listing someone in both is a deny — which makes a deny list safe to reach for in a hurry. And a person beats their groups, so a member of an allowed group can be denied individually, and a member of a denied group can be allowed individually.

An empty members list does not mean nobody. It means that level had nothing to say and the question passes to the groups, which is why allowing one group works perfectly well with both member lists empty. Only step 5 — matched by nothing at either level — is a refusal.

Administrators are allowed by default, skipping the lists entirely. Gating someone who can rewrite these settings achieves nothing, and being quietly excluded from a feature you administer is a confusing way to find out. There is a switch if you disagree.

Blocklist mode

Each of the two questions — who, and where — has a switch turning it from an allow-list into a blocklist: everyone except those denied. It changes exactly one thing, the final step, so every precedence rule above still holds.

It is an explicit setting rather than something inferred from a list being empty. Inferring it was considered and rejected: the same empty field would mean "nobody" or "everybody" depending on a neighbouring field, and it would fail open on a config edit — adding one denied tag would silently expose every other tag on the forum.

Tags work like members, minus the hierarchy: one denied tag on a discussion refuses it even if another of its tags is allowed. Parent tags need no special rule — Flarum attaches the parent whenever a child is selected, so allowing or denying a parent covers its children through the data.

Note that admins bypass the member lists by default but not the tag lists, which default to no bypass. The tag lists are not about who is trusted; they decide which of your members' content may leave the forum, and an admin absent-mindedly mentioning the bot in a private-ish tag is the accident they exist to prevent. Private discussions are refused for everybody, always.

Limits

Two caps, both over a rolling 24 hours, both counted from the audit table so a restart or a deploy cannot hand out a fresh allowance:

When a member is out of quota, the composer tells them before they post — "mentioning @claude_user in this post will not produce an answer" — with the choice to post anyway or go back and edit. Nothing is generated and nothing is billed either way; the alternative designs both cost something for no benefit, since having the bot post "you are out of replies" spends an API call to say that no more API calls are available.

The warning is advisory. The server enforces the cap regardless, and records a skipped audit row so a refusal is never invisible.

Quoting and replying

Claude is given each post's real Flarum mention token in the context it reads (@"Name"#p123), and uses them to quote and reply the way the Reply and Quote buttons do — a real blockquote, a real reply pointer, not a plain-text paraphrase.

Note the reverse does not hold by default: Flarum's Reply arrow and Quote button insert a link to a post, not a mention of an account, so quoting the bot does not summon it. Only an @-mention does. There is a setting to accept quotes as well, off by default — in a thread about the bot, members quote it to talk about it, and it would join every one of those conversations uninvited.

Anything it emits that points at a post or a person it was not shown is stripped before publishing, leaving the bare name behind. A wrong post id would only render as visible junk, but a wrong user id notifies a real member who had nothing to do with the discussion, and a group mention notifies everyone in the group. Only the ids that were in the context survive; flarum/mentions rewrites the display name from the id on parse, so a stale nickname corrects itself.

Tuning without spending money

Prints a gate report — every check, its verdict and the reason, for the post's author against current settings — then the exact context that would be sent, the post count, the heuristic estimate and the real count_tokens figure. Add --send to also call the API and print the reply, still without posting it, or --gate to stop after the gate report.

This is the first thing to reach for when the answer to "why didn't the bot reply to that?" is not obvious.

Use this to iterate on persona_prompt and context_token_budget before letting it near a real thread.

Context strategy

Whole-thread-always is wrong: expensive on long threads, and the middle is mostly noise. Instead:

Posts are sent as their unparsed source (the markdown the author typed), not rendered HTML — cheaper and more faithful.

Privacy

Mentioning the bot sends that discussion's posts — other members' words, under their real display names — to Anthropic. That is the deal; the allow-lists exist so you opt into it deliberately.

An AI-disclosure footer is configurable and recommended.

Cost

One reply ≈ one Messages API call. On claude-opus-5 ($5/$25 per MTok), a short thread costs roughly $0.05 and a full 20k-token context roughly $0.14. Every call's token counts are written to ekumanov_claude_replies, so spend can be reconciled against the console:

Prompt caching is deliberately not used: mentions arrive minutes or hours apart while the cache TTL is five minutes, so cache writes (1.25×) would almost never be read back (0.1×).

Troubleshooting

Symptom Cause
refusing to run on the sync queue in the log Set a real queue driver and run a worker. Running a multi-minute API call inline would hang the composer.
Nothing happens, nothing logged Run claude-reply:test <postId> --gate — it names the gate that refused.
A member stopped getting replies Their per-member cap. skipped rows in the audit table record it, with per_user_daily_limit_reached in error.
no API key configured config.php key missing or the file wasn't reloaded.
Audit row stuck pending The worker never picked the job up.
Audit row failed Read its error column — it holds the API error verbatim (truncated to 255 chars).
Reply cut off mid-sentence max_tokens too low. It caps thinking and visible text together.

Implementation notes

Non-obvious Flarum 2.0 details this depends on, all verified against rc.5:

Licence

MIT


All versions of flarum-ext-claude-reply with dependencies

PHP Build Version
Package Version
Requires flarum/core Version ^2.0
flarum/mentions Version ^2.0
php Version ^8.2
anthropic-ai/sdk Version ^0.42
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package ekumanov/flarum-ext-claude-reply contains the following files

Loading the files please wait ...