Skip to content

What phpbotscout does not do

Documentation usually describes what software does. This page describes what it will not do, which is the other half of the question people actually ask. Every entry here is either not built yet, deliberately unsupported, or a constraint of how the thing works — and each says which.

It cannot answer, post or moderate in Discord yet

Not built. phpbotscout serve connects the Discord gateway and reads the channels on its allowlist. That is all it does with them.

The transport mints every scope read-only, so the reader carries no actor at all: posting, threads, reactions, slash commands and moderation are absent from the type rather than switched off behind a flag. There is no configuration that turns them on.

Answering works today only from the command line, through phpbotscout ask.

Asked about Today
Answering a question in a channel not built
Opening a thread, reacting, or replying not built
Flagging content for moderators not built
Raising a GitLab issue on someone's behalf not built
/ask or /appeal slash commands not built

It cannot look up, export or delete a Discord user's records

Not built, and worth being precise about. There are no per-user records to look up: the only persistent store is the SQLite index over public documentation, which contains no member data at all. No moderation record, no message archive, no per-user history exists in this codebase.

So a request phrased as "delete this user's moderation record" has no operation behind it — not because the request is refused, but because nothing has written one. When moderation does exist, handling a request like that will be a human process, described in what phpbotscout does with your messages, rather than a CLI command.

The bot also does not learn anything about the person asking. ask is one-shot by construction: no conversation is retained between questions, and one person's question is never part of the context for the next person's.

It serves exactly one Discord guild

Deliberate. discord.guilds is a list, and exactly one entry is accepted. Two is a startup error:

2 configured: ingest: more than one guild configured, which is not supported in v1

Multi-tenancy is a v1 non-goal. The list shape exists so that supporting several later is a configuration change rather than a migration of everybody's config file.

It cannot read a channel it was not told about — and it reads more than it keeps

A constraint of Discord, not a choice. Discord's message intents are guild-wide. There is no way to subscribe to only the allowlisted channels, so the gateway delivers every message in the guild and the bot discards the ones it must not read.

Nothing about a message from an unwatched channel is retained — not its content, not its channel, not its author, only one unlabelled counter. See what it reads, and what it keeps.

A thread is read when the channel it hangs off is on the allowlist, without being listed itself. That is not a widening: a thread cannot exist anywhere its parent does not. See threads are covered by their channel.

Direct messages, private channels and voice are not read at all.

It cannot index a repository you name

Deliberate, and a security boundary. There is no configuration key, flag or file that adds a source. The corpus is enumerated from the forge and filtered by a predicate every run.

A configuration file asserting that a repository is public would replace a live check with an operator's memory — and a repository made private yesterday looks identical to one that is still public. See what the bot is allowed to read.

The same applies in reverse: there is no command that removes one source from the index. When a repository stops qualifying, later runs stop writing it.

It cannot use OpenAI, Gemini, or a local model server

A constraint today, and a hard one. Five provider names are compiled in; only claude and claude-local are usable. openai and gemini are refused at construction:

ERRO ask: build openai client: provider openai does not support Config.Stateless

ask builds its client one-shot, and those provider modules do not implement that contract. It is not a setting you can turn off from configuration — see ai for why one-shot is load-bearing.

openai-compatible, which is how you would reach Ollama or a self-hosted endpoint, fails earlier still, because phpbotscout has no configuration key for a provider base URL:

ERRO ask: build openai-compatible client: invalid chat provider base URL hints="ProviderOpenAICompatible requires Config.BaseURL to be set"

Supplying one would not help: it is the same OpenAI client underneath, so it would then be refused for the same one-shot reason.

There is also no way to use one provider for one task and another for a second: ask builds a single client, and there is no second task yet to give a different one to.

A constraint of the current implementation. Ranking is BM25 over SQLite FTS5. There is no embedding model, no vector index and no re-ranking step. A question phrased entirely in words the documentation does not use will not find the page that answers it, however close the meaning.

Two things soften that, and neither removes it: terms are stemmed by the porter tokenizer, and code chunks carry the split form of their identifiers so defaultTakeCount is reachable as "default take count".

There is no configuration key for a relevance threshold. Calibration found that no score separates a question the corpus answers from one whose subject it merely covers — the bands overlap, and a floor set high enough to exclude the second takes 40% of the first with it. --limit is the only retrieval control.

An answer can only be as current as the last successful refresh

A constraint of how indexing works. The index is a snapshot. serve re-reads the corpus every index.refresh_interval — an hour by default — and a source that fails stays at whatever commit it was last indexed at.

A stale index deliberately does not fail readiness. Answering from what is already indexed, with a caveat, beats not answering, and taking the bot out of service would not fix a forge nobody can reach. index status is where staleness surfaces.

It will not answer from issue threads

Deliberate. An answer that exists only in an issue comment is a documentation gap, and the bot is built to surface gaps rather than paper over them. Issue text is never answer content; an issue may only point at documentation or code, and that target must satisfy the corpus rules on its own.

The cost is real: a maintainer's explanation in an old thread cannot be used. See what the bot is allowed to read.

--output json does not change command output

A gap, not a decision. The global --output flag is accepted by every command, but ask, index status and index sources write formatted text regardless. There is currently no machine-readable output from any of them.

There is no released binary

Not yet. No version has been tagged, so there is nothing to go install by version, nothing on a releases page, and phpbotscout update has nothing to update to. Installing means building from source — see Getting started.