Build OpenArc's source adapter
OpenArc ships no code for talking to any post source. It
reaches its source through one small seam you implement locally, for the source the
user is authorized to use, on the user's own account/session. Your job is to write
openarc_adapter.py in the repo root so it satisfies that seam. The user is
responsible for complying with their source's terms of service — surface that, don't
work around it.
The contract
openarc_adapter.py must expose create_source(config) returning an object with two
methods (the PostSource seam in src/openarc/source.py):
def search(self, keyword: str, since: datetime) -> list[Post]: ...
def publish_reply(self, post_id: str, text: str) -> None: ...
Post is openarc.source.Post — id, author_id, author_username, text,
permalink, posted_at (ISO-8601 string). id and author_id must be stable per
post/author (OpenArc dedupes and rate-limits on them).
search returns posts matching keyword, none older than since, newest first.
- A successful search with no matches returns
[]. Authentication failures, rate
limits, request/schema drift, parser failures, and API-level errors must raise an
exception so OpenArc never reports them as an empty market result. For GraphQL-style
APIs, inspect the response body for errors even when HTTP status is 200.
publish_reply posts text as a reply to post_id.
- Read any secrets the source needs (a key, a session token, ...) from the environment
inside the adapter — OpenArc's config knows nothing about them.
- Manage the source's session/auth lazily inside these methods.
Start from openarc_adapter.example.py — copy it to openarc_adapter.py and fill in
the two methods.
How to build it
The user has to supply what only they have: which source, and how their client reaches
it. Ask them for it — don't invent endpoints or guess at a private interface.
- Get the source's shape from the user. The reliable way: ask the user to perform
the action once in their own logged-in browser/app (a search; a reply) and hand you
the resulting request(s) — e.g. "copy as fetch" from the browser's network panel, or
an equivalent capture. That request, made from the user's own session, is the ground
truth for what to reproduce. In DevTools, filter Network requests by
graphql and inspect operationName; for this Threads flow, useful search hints are
SearchResultsQuery and configure_text_only_post. They are search terms, not a
promise that the interface will remain unchanged. Save the capture as a local UTF-8
file instead of pasting it through a PowerShell command line.
- Reproduce it in
search / publish_reply using httpx, mapping the response
into Post objects. Replay the complete captured request when the source uses a
private or versioned web interface; only replace fields known to vary, such as the
query. Do not guess that apparently redundant request fields are safe to remove.
Keep credentials out of the code — pull them from the environment.
- Verify with
openarc pending empty and one real openarc patrol: it should
return posts (or a clean empty result), not raise. Then let the user review drafts in
openarc queue before anything is published.
Windows/PowerShell encoding
Do not put Chinese request bodies or reply text directly inside a PowerShell command,
echo, Out-File default, or cmd /c string. Write a UTF-8 file and pass its path.
For a draft reply containing non-ASCII text, use:
openarc draft <post_id> --text-file <utf8_reply_file>
OpenArc accepts UTF-8 with or without a BOM. Use the harness file writer or an explicit
UTF-8 writer; a console that displays ?? is not proof that the file is corrupted.
For diagnostics in Windows PowerShell, set $OutputEncoding and
[Console]::OutputEncoding to UTF-8 before printing. openarc pending intentionally
emits escaped JSON so non-ASCII text survives every terminal encoding.
When it stops working
Source interfaces change. If patrol starts returning nothing or erroring, the request
you reproduced has drifted — ask the user for a fresh capture and re-fit search /
publish_reply to it. Same skill, same steps.
Keep it narrow
This adapter is the user's personal automation over their own access. Keep it to what the
patrol needs — search and reply — at a human pace. Don't add bulk-scraping, multi-account,
or evasion behavior; if the user asks for those, say no and explain why (it raises both
account and legal risk, and it's outside what this tool is for).
1---2name: setup-source3description: Build the local source adapter OpenArc needs (openarc_adapter.py) so `openarc patrol` can search and reply. Use when `openarc patrol` reports no source adapter is configured, when the user asks to "set up the source" / "build the adapter" / "connect OpenArc to my source", or when it stopped working and needs re-fitting to the source's current interface.4---56# Build OpenArc's source adapter78OpenArc ships no code for talking to any post source. It9reaches its source through one small seam you implement locally, for the source the10**user** is authorized to use, on the user's own account/session. Your job is to write11`openarc_adapter.py` in the repo root so it satisfies that seam. The user is12responsible for complying with their source's terms of service — surface that, don't13work around it.1415## The contract1617`openarc_adapter.py` must expose `create_source(config)` returning an object with two18methods (the `PostSource` seam in `src/openarc/source.py`):1920```python21def search(self, keyword: str, since: datetime) -> list[Post]: ...22def publish_reply(self, post_id: str, text: str) -> None: ...23```2425- `Post` is `openarc.source.Post` — `id`, `author_id`, `author_username`, `text`,26 `permalink`, `posted_at` (ISO-8601 string). `id` and `author_id` must be stable per27 post/author (OpenArc dedupes and rate-limits on them).28- `search` returns posts matching `keyword`, none older than `since`, newest first.29- A successful search with no matches returns `[]`. Authentication failures, rate30 limits, request/schema drift, parser failures, and API-level errors must raise an31 exception so OpenArc never reports them as an empty market result. For GraphQL-style32 APIs, inspect the response body for `errors` even when HTTP status is 200.33- `publish_reply` posts `text` as a reply to `post_id`.34- Read any secrets the source needs (a key, a session token, ...) from the environment35 **inside the adapter** — OpenArc's config knows nothing about them.36- Manage the source's session/auth lazily inside these methods.3738Start from `openarc_adapter.example.py` — copy it to `openarc_adapter.py` and fill in39the two methods.4041## How to build it4243The user has to supply what only they have: which source, and how their client reaches44it. Ask them for it — don't invent endpoints or guess at a private interface.45461. **Get the source's shape from the user.** The reliable way: ask the user to perform47 the action once in their own logged-in browser/app (a search; a reply) and hand you48 the resulting request(s) — e.g. "copy as fetch" from the browser's network panel, or49 an equivalent capture. That request, made from the user's own session, is the ground50 truth for what to reproduce. In DevTools, filter Network requests by51 `graphql` and inspect `operationName`; for this Threads flow, useful search hints are52 `SearchResultsQuery` and `configure_text_only_post`. They are search terms, not a53 promise that the interface will remain unchanged. Save the capture as a local UTF-854 file instead of pasting it through a PowerShell command line.552. **Reproduce it in `search` / `publish_reply`** using `httpx`, mapping the response56 into `Post` objects. Replay the complete captured request when the source uses a57 private or versioned web interface; only replace fields known to vary, such as the58 query. Do not guess that apparently redundant request fields are safe to remove.59 Keep credentials out of the code — pull them from the environment.603. **Verify** with `openarc pending` empty and one real `openarc patrol`: it should61 return posts (or a clean empty result), not raise. Then let the user review drafts in62 `openarc queue` before anything is published.6364## Windows/PowerShell encoding6566- Do not put Chinese request bodies or reply text directly inside a PowerShell command,67 `echo`, `Out-File` default, or `cmd /c` string. Write a UTF-8 file and pass its path.68- For a draft reply containing non-ASCII text, use:6970 ```text71 openarc draft <post_id> --text-file <utf8_reply_file>72 ```7374 OpenArc accepts UTF-8 with or without a BOM. Use the harness file writer or an explicit75 UTF-8 writer; a console that displays `??` is not proof that the file is corrupted.76- For diagnostics in Windows PowerShell, set `$OutputEncoding` and77 `[Console]::OutputEncoding` to UTF-8 before printing. `openarc pending` intentionally78 emits escaped JSON so non-ASCII text survives every terminal encoding.7980## When it stops working8182Source interfaces change. If `patrol` starts returning nothing or erroring, the request83you reproduced has drifted — ask the user for a fresh capture and re-fit `search` /84`publish_reply` to it. Same skill, same steps.8586## Keep it narrow8788This adapter is the user's personal automation over their own access. Keep it to what the89patrol needs — search and reply — at a human pace. Don't add bulk-scraping, multi-account,90or evasion behavior; if the user asks for those, say no and explain why (it raises both91account and legal risk, and it's outside what this tool is for).