Metadata-Version: 2.4
Name: papyrus-newsroom
Version: 2.0.0.dev50
Summary: Papyrus newsroom Python tools and CLI.
License-Expression: MIT
License-File: LICENSE
Requires-Python: >=3.12,<3.14
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Provides-Extra: markus
Provides-Extra: newsroom
Provides-Extra: priming
Requires-Dist: Pillow (>=10,<12) ; extra == "markus"
Requires-Dist: PyYAML (>=6.0.2,<7.0.0)
Requires-Dist: anthus-markus (>=0.7.0,<1.0.0) ; extra == "markus"
Requires-Dist: biblicus (>=1.15.0,<2)
Requires-Dist: biblicus[dspy,markitdown,neo4j,ner,openai,topic-modeling,web] (>=1.15.0,<2) ; extra == "newsroom"
Requires-Dist: boto3 (>=1.34.0,<2.0.0) ; extra == "markus"
Requires-Dist: boto3 (>=1.34.0,<2.0.0) ; extra == "newsroom"
Requires-Dist: citeproc-py (>=0.8.2,<1.0.0)
Requires-Dist: fastapi (>=0.115,<1) ; extra == "priming"
Requires-Dist: humanus (>=0.33,<0.34)
Requires-Dist: markitdown[all] (>=0.1.0,<1.0.0) ; extra == "newsroom"
Requires-Dist: strawberry-graphql[fastapi] (>=0.280,<1) ; extra == "priming"
Requires-Dist: tactus (>=0.53.4,<1) ; extra == "newsroom"
Requires-Dist: tiktoken (>=0.12.0,<0.13.0) ; extra == "newsroom"
Requires-Dist: uvicorn (>=0.30,<1) ; extra == "priming"
Project-URL: Homepage, https://github.com/AnthusAI/Papyrus
Project-URL: Repository, https://github.com/AnthusAI/Papyrus
Description-Content-Type: text/markdown

# Papyrus

Papyrus is an open-source system that keeps a continuous, steerable feed of insight about the subjects you choose: it watches sources, decides what is relevant from your include/exclude labels, has editor agents write and check it up to your policies, and publishes it for people and agents.

You are focused on a topic. For us, it is AI/ML information systems. For you, it might be golf club technology, oil markets, local politics, or any other beat worth watching closely. The beat is configuration, not code. The current AI/ML corpus is pilot content, not an application assumption. A Papyrus publication changes subject by changing publication configuration, corpus set, category/graph steering state, edition plans, and worker instructions.

Research agents monitor the beat, update a publication-specific knowledge base, and surface developments. Editor agents turn those signals into assignments. Reporter agents prepare private reporting packets: the verified facts, source trail, open questions, risks, angle, and copywriter brief an editor needs before commissioning reader-facing copy. Copywriter agents turn selected packets into draft Items for review. You steer as much or as little as you want, and editors decide what is published.

## What Papyrus does

Status: Live, Beta, or Not built yet. Each line links to the page that says what exists.

- **Publishes for people and agents.** Static Markus sites with Markdown twins, `llms.txt`, `Accept: text/markdown`, page actions, feeds and a sitemap. Live. [Agent-readable sites](docs/agent-readable-sites.md), [building a static site](docs/building-a-papyrus-static-site.md).
- **Steers from your decisions.** Doctrine, include and exclude labels, category steering. Live. The relevance Cyclotron and per-Section Cyclotron are Beta; steering by votes, ratings and comments is Not built yet. [Steering and relevance](docs/steering-and-relevance.md).
- **Watches sources.** The Hacker News Monitor is Beta. Email, Slack and research dispatch are Live. General RSS monitors, many monitors per publication and X search are Not built yet. [Sources and monitoring](docs/sources-and-monitoring.md).
- **Runs editor agents.** Researcher, editor, reporter and copywriter procedures, editorial checks on by default, story versions and a reporting trail. Live. [Editor agents](docs/editor-agents.md).
- **Keeps a knowledge base.** Concepts wiki for editors, topics, graph, context packs: Live. Trending concepts report: Beta. Public wiki, topics and trends: Not built yet. [Knowledge base](docs/knowledge-base.md).
- **Collects newsletter signups.** Signup capture is Live. Sending is Not built yet. [Newsletter](docs/newsletter.md).

To start a new publication from a pile of files, follow
[`docs/new-publication-from-corpus.md`](docs/new-publication-from-corpus.md).
That workflow defines the corpus accession shape, reference-prospect intake,
accepted-only analysis manifests, authoritative labels, topic granularity
profiles, and `analysis.reindex` assignment path used to bootstrap a knowledge
base from scratch.

## What is in the box

- **A newsroom.** `/newsroom` is the operations workspace: topics, sections, doctrine, references, assignments, editions. Agents research and report in private; editors steer and decide. See [Newsroom operations](docs/newsroom-operations.md) and [How Papyrus works](docs/how-papyrus-works.md).
- **A knowledge base.** Accepted categories, references and a semantic graph give agents context beyond vector search. Search it with `knowledge-query` ([internal knowledge research](docs/internal-knowledge-research.md)).
- **A reader.** Either a newspaper-style Next.js reader laid out by a Pretext solver ([layout system](docs/layout-system.md)) or a static Markus site served from S3 and CloudFront ([site hosting](docs/site-hosting.md)).
- **A CLI.** `papyrus` signs every request with your AWS credentials (SigV4); there is no token to manage ([operator CLI](docs/operator-cli.md), [recipes](docs/python-cli-and-testing.md)).

## How a Papyrus Publication Fits Together

![How a Papyrus publication fits together: editors use the newsroom UI in the CMS app; Save calls the AppSync GraphQL API, and the content-actions Lambda renders only the affected pages into a versioned S3 site bucket served by CloudFront; a renditions Lambda makes images at upload; the Pretext kind is a Next.js server on Amplify that reads published models as a guest](docs/images/publication-architecture.svg)

Text version of the picture:

- **One CMS app per site.** Editors sign in with Google to the newsroom UI. Every change goes through the GraphQL API (AppSync), which stores items and published items in DynamoDB. Uploaded images go to the media bucket.
- **Save is live.** For a Markus site (publication kind `s3-projection`, the default for new sites), the `content-actions` Lambda behind the Save, Publish and Unpublish mutations saves the item and then renders only the pages that depend on it (the item page, the listings, tags, home, sitemap) into a versioned S3 site bucket. There is no build job and no Republish button; a change is visible within seconds. Writes happen in an order that never leaves a link to a missing page.
- **Images are made at upload.** An S3 event on the media bucket starts the `renditions` Lambda, which writes the responsive image files and a small size file into the site bucket. Page renders read the size file and never decode an image.
- **CloudFront serves the bucket.** The site's own CloudFront stack (with its own certificate) reads the private bucket and runs small edge functions for redirects and for `/x/` to `/x/index.html`. After each projection the Lambda invalidates the changed paths in one call; a run that would purge more than 10 paths sends a single `/*` instead, which CloudFront bills as one path.
- **Pretext is the alternative kind.** A Pretext site is a Next.js server on Amplify that renders pages on request from the published models. A publish tells it to revalidate, and a page lives about a minute at most.
- **Guests are read-only.** The public (guest) GraphQL surface can read the published models and `media/*`, nothing else, and no model or mutation allows a guest to write.
- **Where Git fits.** Git holds code, theme and the site's projector, not articles. Content lives in DynamoDB; the site can always be re-projected from it with `papyrus ops content project --all`.

Details: [How a publish flows](docs/how-a-publish-flows.md) (for editors) and [Site hosting](docs/site-hosting.md) (for operators).

## Quick start

Requirements: Node and npm, Python 3.12 or 3.13, [Poetry](https://python-poetry.org/), and an AWS profile for anything that touches the cloud.

```bash
npm install
poetry install
cp .env.example .env     # app-level settings only; never credentials
npm run dev:127          # http://127.0.0.1:3001 (prefer 127.0.0.1 over localhost)
```

Settings you need for the features named:

| Variable | Used for |
| --- | --- |
| `PAPYRUS_GRAPHQL_ENDPOINT` | CLI and agents talking to a deployed AppSync API |
| `PAPYRUS_INBOUND_EMAIL_DOMAIN` | Addresses for inbound email submissions and replies |
| `PAPYRUS_PUBLIC_SITE_BASE_URL` | Absolute links in submission feedback (or `publicSite.baseUrl` in the Papyrus config) |

The shell environment wins over `.env`. See `.env.example` for the full list and [docs/inbound-email-submissions.md](docs/inbound-email-submissions.md) for the email flow.

For a cloud sandbox:

```bash
AWS_PROFILE=<profile> npm run sandbox          # provisions an Amplify sandbox
AWS_PROFILE=<profile> npm run seed:amplify     # users, sections, doctrine, procedures
poetry run papyrus ops content seed-edition    # fixture edition, articles and media
```

Production deploys run from `main` through the DevOps pipeline. Do not run `ampx pipeline-deploy` locally.

## Commands

## Commands

```bash
npm run dev
npm run dev:127
npm run lint
npm run typecheck
npm run build
poetry install
poetry run papyrus --help
poetry run papyrus procedures execute-tactus 'return api_list{}'
poetry run python procedures/newsroom/tests/test_newsroom_tools.py
npm run sandbox
npm run seed:amplify
poetry run papyrus ops content inspect
poetry run papyrus ops categories import-config --config corpora/papyrus-steering.yml
poetry run papyrus sections import --config corpora/papyrus-newsroom-sections.yml
poetry run papyrus ops categories import-steering --config corpora/papyrus-steering.yml --corpus-key <key>
poetry run papyrus ops categories import-steering --bundle <steering-export.json>
poetry run papyrus knowledge topics export-category-set --category-set <id> --output <accepted-category-set.json>
poetry run papyrus ops categories import-projection --config corpora/papyrus-steering.yml --target-corpus-key <key> --authority-corpus-key <key> --bundle <projection.json>
poetry run papyrus knowledge concepts import-types --config corpora/papyrus-semantic-relation-types.yml
poetry run papyrus knowledge concepts backfill --config corpora/papyrus-semantic-relation-types.yml
npm run test:bdd
npm run test:bdd:backend
npm run test:bdd:agent-live
```

Test suites and verification: [docs/verification.md](docs/verification.md), [docs/python-cli-and-testing.md](docs/python-cli-and-testing.md), [docs/layout-scenario-tests.md](docs/layout-scenario-tests.md).

## Where to read next

- [docs/README.md](docs/README.md): index of every documentation page.
- [AGENTS.md](AGENTS.md): the hard rules for agents, each with its enforcement.
- [CONTRIBUTING_AGENT.md](CONTRIBUTING_AGENT.md): Kanbus workflow for the PPY board.
- [docs/new-publication-from-corpus.md](docs/new-publication-from-corpus.md): start a new publication from a pile of files.
- [docs/code-map.md](docs/code-map.md): where the main files live.

---

Built by [Anthus AI Solutions](https://anth.us). We run this class of system in production.

If you need this operated, not just cloned, [talk to us](https://anth.us).

