Skip to content

docs: add PPE documentation - #82

Merged
shaneutt merged 29 commits into
praxis-proxy:mainfrom
araujof:docs/ppe
Sep 9, 2026
Merged

docs: add PPE documentation#82
shaneutt merged 29 commits into
praxis-proxy:mainfrom
araujof:docs/ppe

Conversation

@araujof

@araujof araujof commented Sep 6, 2026

Copy link
Copy Markdown
Member

Create PPE documentation.

Closes: #68

Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Loading a document is not enough: the policy body must compile too.

Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Both configs were already in the tree with nothing invoking them.

Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
@araujof araujof changed the title docs: refine PPE documentation docs: add PPE documentation Sep 6, 2026
@araujof araujof added the documentation Improvements or additions to documentation label Sep 6, 2026
@araujof araujof moved this from Backlog to In progress in Praxis Policy Engine (PPE) Sep 6, 2026
@araujof araujof added this to the 0.3.0 milestone Sep 6, 2026
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
@araujof
araujof marked this pull request as ready for review September 8, 2026 01:29
@araujof
araujof requested a review from a team September 8, 2026 01:29
@araujof
araujof requested a review from terylt as a code owner September 8, 2026 01:29
@araujof araujof moved this from In progress to Review in Praxis Policy Engine (PPE) Sep 8, 2026
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Indentation was leading whitespace, which only renders where
`xml:space="preserve"` is honoured. Each line now carries an explicit `x`,
so the YAML shape reads in any renderer. The legend comments need `dx` for
the same reason.

The sketch also shows `post_invocation:` and `args:`, which it did not.

Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>

@praxis-bot praxis-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid documentation addition -- the test harness that validates every fenced YAML/APL block against the real parsers is particularly well designed. Two naming mismatches to fix before merge.

Comment thread CONTRIBUTING.md Outdated
Comment thread .markdownlint.yaml
Signed-off-by: Teryl Taylor <terylt@ibm.com>

@terylt terylt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Fred, Overall, nice work! I just have some relatively minor feedback.

Reviewed the new pages against the parser and the config model. The
writing is strong and the docs_examples harness is the right idea:
loading 44 of 82 YAML blocks through the real parse_config plus policy
compiler, with a floor assertion so the walk cannot silently check
nothing, is a better guarantee than most doc sets have.

Some corrections are going up as separate commits on this branch:
effects.md, extensions.md, threat-model.md, pipeline.md,
builtins.md, and quickstart.md. The items below are the ones worth
your eyes first. Each is verified against the source, with file and
line.

1. A flat phase list is a load error, not an equivalent spelling

docs/content/apl/index.md:67

The pre_invocation: / post_invocation: lists may also be written
flat on the route (without the authorization: wrapper); both forms
are equivalent.

They are not equivalent. ROUTE_STRUCTURAL_KEYS (config.rs:1256) carries
no such key, and a_route_writing_a_phase_list_flat_is_rejected pins the
error. configuration.md and identity-delegation.md:166 both state the
rule correctly, so this line also contradicts two other pages in the PR.

Suggested:

Both phase lists nest under `authorization:`. Writing `pre_invocation:` or
`post_invocation:` directly on a route is a load error naming the key, and an
empty `authorization:` block is rejected.

2. Prompt hook names, and a removed phase name

docs/content/cmf.md:45 names cmf.prompt_pre_fetch /
cmf.prompt_post_fetch. The hooks are cmf.prompt_pre_invoke /
cmf.prompt_post_invoke (visitor.rs:55). Only resource uses _fetch,
and pipeline.md has the table right.

cmf.md:48 then refers to a route's policy phase. policy is a
removed key: REPLACED_KEYS (config.rs:1064) maps it to
authorization.pre_invocation.

3. Plugin mode has six values

docs/content/configuration.md:94 gives sequential or concurrent.
PluginMode (plugin.rs:525) is Sequential, Transform, Audit,
Concurrent, FireAndForget, Disabled. pipeline.md documents all
six, and patterns.md tells the reader to use mode: audit for shadow
rollout, which the configuration table says does not exist.

4. A restrict example that would not load

docs/content/apl/restrict.md:139 writes on_allow: as a sibling of
cedar::

pre_invocation:
  - cedar:
      action: 'Action::"read"'
      resource: { type: Dataset, id: eu_data }
    on_allow:
      - restrict: { allow_regions: [eu] }

The parser requires exactly one key per step map, so this fails with
"step map must have exactly one key (PDP call signature, when:/do:,
or a predicate: [effects...] shorthand)". pdp.md and effects.md
both nest the reaction block inside the dialect key, which is the form
that loads.

This one is the argument for the next item: the block is marked
<!-- validate: fragment -->, so nothing checked it.

5. Five examples opt out of validation and should not

apl/delegation.md:92,103,120, apl/restrict.md:139, and
use-cases.md:176 each write a bare pre_invocation: with no
authorization: wrapper, behind <!-- validate: fragment -->.

The harness comment is right that fragment should be uncomfortable:
"it asserts nothing. It is correct for a deliberately invalid example,
the 'before' half of a migration note, and for a snippet no document
could hold." These are none of those. They are ordinary examples, and
one of them (item 4) was broken.

phase-list wraps a rule list in the smallest document that carries it,
so switching the marker and dropping the pre_invocation: line both
validates them and shows the accepted spelling. use-cases.md:176 is a
route entry, so it wants the authorization: wrapper and a routes:
key, after which it validates as a full document.

That takes the fragment count from 14 to 9. The remaining nine are
genuine config sub-blocks (claim_map:, cache:,
client_secret_source:) that no document could hold.

6. Identity is the one control the use cases do not show

docs/content/use-cases.md section 1 is titled "Identity-aware tool
access" and shows only the gate:

routes:
  - tool: get_compensation
    authorization:
      pre_invocation:
        - "require(role.hr)"

Every other section shows its mechanism: section 5 has the whole
pii-scan plugin block, section 7 has the Cedar and CEL blocks. Section
1 asserts in prose that the demo "resolves two identities per request,
the human (X-User-Token) and the client (Authorization), each
validated by its own identity/jwt plugin against Keycloak" and shows
none of it.

That is the one control everything else on the page depends on. The
persona table is entirely identity-driven, and section 2's redaction
keys off perm.view_ssn.

Suggest showing both resolvers and global.authentication: before the
gate, taken from the demo's policy.yaml so the page's "each snippet
comes from the live configuration" claim holds. A trimmed version loads
through the harness as a full document. Two details worth your call:

  • The demo config carries insecure_http: true on both JWKS URLs, which
    is correct for http://localhost:8081 and wrong to copy. Keeping it
    with the demo's own "localhost dev, never production" comment seems
    better than dropping it and leaving a snippet that cannot work.
  • Both resolvers use claim_mapper: standard, but
    identity-delegation.md says Keycloak "puts its roles claim where no
    preset can name it" and needs a hand-written map. The demo works, so
    presumably the realm is shaped to suit standard. Those two pages
    read as being in tension; you would know which is right.

7. make lint-docs does not exist

.markdownlint.yaml:2 and CONTRIBUTING.md:66 both name it. The
Makefile target added in this PR is docs-lint (Makefile:241), with
docs-links beside it (Makefile:229). CONTRIBUTING does not mention
docs-links at all.

One larger question, not a file change

docs/content/ is Hugo's content directory, and these are CPEX's pages:
same filenames, same tree. What did not come across is
docs/hugo.toml, the hugo-book theme, layouts/, and the
docs-build.yaml / docs-deploy.yaml workflows. So the layout implies a
site and nothing builds one.

That has a knock-on effect on index.md. On the CPEX site the sidebar
carried navigation, which freed _index.md to be a landing page:
headline, the tagline "A policy enforcement runtime for AI agents", the
reference monitor sentence, and the positioning paragraph about existing
authorization systems answering whether a request is allowed while
CPEX answers what pipeline should execute. Here index.md has to be
both landing page and sidebar substitute, and it currently reads as a
28 link directory. The positioning paragraph has no equivalent anywhere
in the tree.

Related: bd5c807 replaced the index's opening

PPE is a policy enforcement runtime for AI agents: a deterministic
Reference Monitor that mediates every operation an agent triggers.

with "a typed policy evaluation and enforcement runtime for AI
middleware". Understandable if the goal was to keep the reference monitor
claim to the pages that argue for it, but the replacement trades a
concrete audience ("AI agents") for a vaguer one ("AI middleware"), and
the index is now the only page that will not say what PPE sits between.

Also left behind: the 21 file tutorial (00-setup through
18-attributes plus a capstone). Possibly deliberate, since the harness
comment notes the ported pages "were written against a config shape and a
language this repository has since changed", but its absence is worth
being a stated decision rather than a silent one.

Is the site a follow-up, or is GitHub-rendered markdown the intended
endpoint? The answer changes what index.md should be.

One note on a comment in the code

capability_namespaces.rs:102 says security labels "are not extracted
into discrete bag keys today". security.rs:152 does
bag.set("security.labels", labels). The docs picked that comment up
and repeated it; the comment is what should change. Not part of this PR,
but worth an issue so the next reader is not misled the same way.

Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
@shaneutt
shaneutt self-requested a review September 9, 2026 00:32
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
@araujof

araujof commented Sep 9, 2026

Copy link
Copy Markdown
Member Author

Hi Fred, Overall, nice work! I just have some relatively minor feedback.
...

Thanks! Addressed comments.

@terylt terylt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Signed-off-by: Frederico Araujo <araujof@users.noreply.github.com>
@shaneutt
shaneutt merged commit 753d3c7 into praxis-proxy:main Sep 9, 2026
7 checks passed
@github-project-automation github-project-automation Bot moved this from Review to Done in Praxis Policy Engine (PPE) Sep 9, 2026
@araujof
araujof deleted the docs/ppe branch September 9, 2026 04:12
mkoushni added a commit to mkoushni/policy that referenced this pull request Sep 9, 2026
Keep the safety-invariants changelog under Unreleased alongside the
PPE documentation entry from praxis-proxy#82.

Signed-off-by: mkoushni <mkoushni@redhat.com>
mkoushni added a commit to mkoushni/policy that referenced this pull request Sep 9, 2026
Keep the CMF extensions-bag changelog under Unreleased alongside the
PPE documentation entry from praxis-proxy#82.

Signed-off-by: mkoushni <mkoushni@redhat.com>
terylt added a commit to terylt/policy that referenced this pull request Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

docs: port the PPE core reference documentation from CPEX

4 participants