> ## Documentation Index
> Fetch the complete documentation index at: https://metalworks.lab2a.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Extending metalworks

> Every layer is swappable — bring your own model, corpus, search, or storage, or compose the building blocks into your own product.

Every layer is swappable — bring your own model, corpus, search, or storage, or
compose the building blocks into your own product. The `Metalworks` facade is the
easy path; underneath it is a kit of small, independent pieces. This page is the
map: what each piece is, and how to swap or compose it.

## Swappable protocols

Each protocol is `runtime_checkable` and has a default implementation behind a
pip extra. Implement the protocol and pass your object anywhere the default is
expected.

| Protocol                                                             | Import                                                                       | Default(s)                                                                    | How-to                                     |
| -------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ------------------------------------------ |
| `ChatModel`                                                          | `metalworks.llm`                                                             | Anthropic / OpenAI / Google / OpenAI-compatible / Claude Code (keyless floor) | [Custom ChatModel](/docs/custom-chatmodel) |
| `EmbeddingProvider`                                                  | `metalworks.embeddings`                                                      | Google, OpenAI, local fastembed (keyless floor)                               | [Protocols](/docs/protocols)               |
| `SearchProvider`                                                     | `metalworks.search`                                                          | Exa, Tavily, Parallel, Firecrawl, Claude Code (keyless floor)                 | [Protocols](/docs/protocols)               |
| `ItemSource` (grounding) / `MagnitudeProvider` / `DiscoveryProvider` | `metalworks.research.sources` / `…sources.magnitude` / `…research.discovery` | Reddit, Stack Exchange, GitHub, web, … (see the [catalog](/docs/sources))     | [Build a source](/docs/build-sources)      |
| `CorpusReader` / `CommentSource`                                     | `metalworks.research.deps`                                                   | Arctic Shift                                                                  | [Use your own corpus](/docs/custom-corpus) |
| storage repos                                                        | `metalworks.stores`                                                          | `MemoryStores`, `SqliteStores`                                                | [Bring your own store](/docs/custom-store) |

A **source** is the seam that turns "Reddit research" into "research over any source". It comes
in three lanes — a **grounding** connector that yields quotable records, a **magnitude**
provider that attaches an absolute number to a theme, or an agentic **discovery** provider that
reaches the long tail. Each is its own small protocol, registered append-only; see
[Build a source](/docs/build-sources).

Anything you don't pass to `Metalworks(...)` is resolved from the environment.
Anything you do pass is used verbatim — that's how you swap a layer.

```python theme={null}
from metalworks import Metalworks
from my_stack import MyChatModel, MyCorpus

mw = Metalworks(chat=MyChatModel(), reader=MyCorpus())   # swap two layers, keep the rest
```

## Composable functions

You don't have to use the facade or the end-to-end pipelines. The steps are
public functions you can wire into your own flow.

**Research steps** (`metalworks.research`):

* `pick_target_subreddits(deps, brief=...)` — LLM-suggested communities.
* `run_exploration_triage(deps, ...)` — three-bucket relevance triage.
* `hydrate_submissions(...)` / `hydrate_comments(...)` — pull a corpus into a repo.
* `synthesize(deps, ...)` — cluster comments into ranked insights.
* `web_research(deps, ...)` — web findings, backed by real quotes or source URLs.
* `triangulate(deps, ...)` — link Reddit clusters to web findings.
* `run_research(deps, brief=...)` — the whole thing, if you want it.

**Functions over a finished report** (`metalworks.research`) — each takes a
`DemandReport` and traces its output back to the report's real quotes:

* `build_positioning_brief(deps, report)` — your positioning angle + a price read,
  backed by real quotes (`metalworks.research.synthesis`).
* `run_competitor_map(deps, report)` — direct / adjacent / status-quo rivals,
  each with an exploitable gap backed by a real complaint.
* `build_spec_from_report(deps, report, positioning=None, surface="auto")` /
  `scaffold(spec, report, dest)` (`metalworks.build`) — a `BuildSpec` (each
  feature mapped to a real demand cluster; with `surface="auto"` it also picks the
  surface + a rationale and sketches feature-grounded screens) + a project scaffold
  for your own coding agent. metalworks specs and scaffolds; it writes no product
  code. See the [Build spec](/docs/build-spec).
* `build_channel_strategy(deps, report, positioning=None)` / `distribution_requirements(channels)` —
  the **test→focus** channel experiments + the embedded-loop / conversion-surface build requirements.
* `build_channel_assets(deps, report, channels, positioning=None)` /
  `build_data_asset(deps, report, kind="complaint_index")` — drafting-only channel-shaped assets
  (never posts) + a corpus-derived data report with real counts and permalinks.
* `build_geo_plan(deps, report)` / `plan_distribution(report, channels)` / `channel_metrics(channels)` —
  the GEO / LLM-citability stream, the pushes-and-streams plan, and the per-channel success metrics.
  See [Distribution](/docs/distribution).

These are also on the `Metalworks` facade —
`mw.positioning(research)`, `mw.landscape(...)` (the competitive map + existing solutions),
`mw.design(...)`, `mw.build_spec(...)` / `mw.scaffold(...)`,
`mw.channel_strategy(...)` / `mw.channel_assets(...)` / `mw.data_asset(...)` / `mw.geo(...)` /
`mw.distribution_plan(...)` — which thread
the one resolved `ResearchDeps` for you. See the [walkthrough](/docs/walkthrough).

**Reddit + discovery** (`metalworks.reddit`, `metalworks.discovery`):

* `RedditSearch` — search, comments, subreddit rules. No OAuth needed.
* `fetch_subreddit_intel(...)`, `fetch_inbox(...)`, `RedditOAuth` — intel, inbox, posting.
* `filter_post(model, post, context)` — is this thread worth engaging?
* `draft_reply(chat, post, persona, account_type, context)` — draft a reply in a voice.
* `heuristic_check(text)` / `llm_judge(...)` — the deterministic gate, then the escalation.
* `run_discovery(deps, queries=...)` — the whole filter → generate → gate loop.

See [Build your own loop](/docs/build-your-own) for composing the discovery
building blocks into your own product, and the
[Demand research guide](/docs/demand-research) for composing the research steps.

## Verify your swaps

The conformance suites ship as a public module so you can check a custom backend
or adapter against the same tests the defaults pass:

```python theme={null}
from metalworks.testing import check_all_repos
check_all_repos(MyStore(), corpus_rows=1500)   # incl. the >1000-row pagination case
```
