Skip to content

docs(adr): adopt gh-aw safe outputs reference model - #6614

Open
cgwalters wants to merge 1 commit into
fullsend-ai:mainfrom
cgwalters:adr-safe-outputs
Open

cgwalters wants to merge 1 commit into
fullsend-ai:mainfrom
cgwalters:adr-safe-outputs

Conversation

@cgwalters

Copy link
Copy Markdown
Contributor

Fullsend needs a safer boundary than broadly privileged post-scripts without making its agent model dependent on one forge. Record gh-aw as the migration target for compatible GitHub writes and as guidance for a separate provider-neutral design covering GitLab, Jira, and Forgejo.

Assisted-by: https://github.com/cgwalters/cgwalters#llms

@cgwalters
cgwalters requested a review from a team as a code owner August 25, 2026 22:13
@github-actions

Copy link
Copy Markdown

E2E tests did not run

E2E tests run automatically for org/repo members and collaborators on pull requests.

For other contributors, a maintainer must add the ok-to-test label after the latest push.

See E2E testing guide for details.

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Tip of the day
💡 Did you know, you can hide the parts of a finding you never read, like the evidence or the agent prompt

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Adopt gh-aw safe outputs as the GitHub side-effect model

📝 Documentation 🕐 10-20 Minutes

Grey Divider

AI Description

• Records gh-aw safe outputs as the migration target for compatible GitHub writes.
• Preserves Fullsend-specific policy controls during operation-by-operation migration.
• Defines a separate provider-neutral direction for Jira, GitLab, and Forgejo.
Diagram

graph TD
  A["Read-only agent"] --> B["Typed requests"] --> C["GitHub stanza"] --> D["Workflow compiler"] --> E["gh-aw jobs"] --> F["GitHub writes"]
  B --> G["Generic tool"] --> H["Other providers"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Use gh-aw custom outputs for every provider
  • ➕ Reuses one safe-output framework and workflow execution model.
  • ➕ Avoids designing a separate generic tool initially.
  • ➖ Couples GitLab, Jira, and Forgejo integrations to GitHub Actions.
  • ➖ Requires provider-specific schemas and custom application jobs.
2. Build one provider-neutral system immediately
  • ➕ Provides a uniform contract across all forges and trackers.
  • ➕ Avoids dependence on gh-aw conventions and release behavior.
  • ➖ Duplicates mature GitHub validation and permission controls.
  • ➖ Expands design scope and delays reduction of current post-script privileges.

Recommendation: The hybrid approach is best: migrate compatible GitHub operations incrementally to gh-aw while retaining deterministic Fullsend policy logic, then design the provider-neutral contract separately. This gains an established least-privilege boundary without making non-GitHub integrations depend on GitHub Actions.

Files changed (4) +113 / -2

Documentation (4) +113 / -2
0093-reuse-gh-aw-safe-outputs-for-github-side-effects.mdRecord the gh-aw safe-output adoption decision +104/-0

Record the gh-aw safe-output adoption decision

• Adds accepted ADR 0093, selecting gh-aw safe outputs as the operation-by-operation migration target for compatible GitHub writes. It preserves Fullsend-specific policy controls and separates the future provider-neutral safe-output contract from gh-aw’s GitHub Actions model.

docs/ADRs/0093-reuse-gh-aw-safe-outputs-for-github-side-effects.md

architecture.mdAdd safe side effects to the architecture decisions +7/-0

Add safe side effects to the architecture decisions

• Documents the future 'github.safe-outputs' configuration and compiler path to gh-aw workflow frontmatter. It also records gh-aw as guidance, rather than the contract, for a generic cross-provider tool.

docs/architecture.md

platform-nativeness.mdConnect gh-aw security architecture to Fullsend’s migration +1/-1

Connect gh-aw security architecture to Fullsend’s migration

• Links the platform-nativeness analysis to ADR 0093 and clarifies that Fullsend will reuse the safe-output model while retaining forge independence.

docs/problems/platform-nativeness.md

security-threat-model.mdRefine the side-effect threat model +1/-1

Refine the side-effect threat model

• Distinguishes today’s privileged post-scripts from the planned read-only-agent and permission-controlled-job boundary. It also clarifies that structural validation cannot guarantee semantically proportionate agent output.

docs/problems/security-threat-model.md

@github-actions

github-actions Bot commented Aug 25, 2026

Copy link
Copy Markdown

Site preview

Preview: https://9117c072-site.fullsend-ai.workers.dev

Commit: 572258c0be46123d386ea4716447b68eb0717c56

@codecov

codecov Bot commented Aug 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@rh-hemartin

Copy link
Copy Markdown
Member

In general sounds good to me, but a few points:

  • The ADR is too verbose, I think the point can be made with less text.
  • The ADR focuses too much on GH's safe-outputs, it interjects it everywhere, making it difficult to follow the reasoning. I see why we want to use it as a reference, or even reuse it as stated here, I will keep it to the Decision section so the ADR reads something like "given this problem, and this solution, safe-outputs already does it, so we may as well adopt its schema".
  • It is not clear if the decision is to drop the post-script system or not. I think the ADR proposes that with too many words. If that is the case, make it clearer (I think this is the phrase that says "eventually drop post scripts": For GitHub-specific agent side effects, Fullsend will adopt gh-aw safe outputs as the target replacement for compatible writes currently performed by privileged post-scripts.).
  • Implementing this we lose the flexibility of the post-scripts, not that many people would use it I guess. Do we want to retain it for advanced usage?
  • I don't think this phrase This separation limits the effect of prompt injection or a compromised agent: the agent cannot turn its requested operation into an arbitrary GitHub API write. is completely true. It reads as if fullsend has no separation, and the post-script does this. Basically if any agent wanted to delete issues it could not, as that is controlled by the post-script. If the post script does not have the logic to close issues, then no issues are closed. It is true that is has no limits, for example if the retro agent wants to open 10 followup issues, it can, the post-script allows it. But if you compromise an agent the post-script handles part of it. Not that this changes anything, just nitpicking on some statements.

Could you bring this to the contributor's meeting for further discussion?

See https://blog.verbum.org/2026/08/21/agentic-ai-and-software-forges/

I believe GH-AW is a reference baseline, and some aspects of how parts
of agents do writes is less secure than what the GH-AW safe outputs
functionality provides.

We should just reuse it instead of reinventing it. Declare too that
we also aim to generalize a safe-outputs style system beyond GitHub.

Assisted-by: https://github.com/cgwalters/cgwalters#llms
Signed-off-by: Colin Walters <walters@verbum.org>
@rh-hemartin

Copy link
Copy Markdown
Member

Thanks for the rewrite. Is safe-outputs an executable? By the wording it looks like it as per "will migrate to safe-outputs". I think the wording should be "will migrate to a safe-outputs like schema and mode of operation, where forge operations will be carried on the CLI instead of the post-script"

@cgwalters

cgwalters commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the rewrite. Is safe-outputs an executable? By the wording it looks like it as per "will migrate to safe-outputs". I think the wording should be "will migrate to a safe-outputs like schema and mode of operation, where forge operations will be carried on the CLI instead of the post-script"

Yes, this is an important decision as it's influenced by the whole system architecture. A thing I find extremely compelling about GH-AW is one can describe it in a single sentence: "A compiler that takes markdown agent steps with YAML frontmatter defining its event triggers and output restrictions, and generates Github Actions."

(I think it'd be quite challenging to describe fullsend or various other projects in this space as comprehensively in a single sentence description)

The reason the architecture matters a lot here because the safe outputs implementation is heavily influenced by that compilation phase, see e.g.
https://github.github.com/gh-aw/specs/safe-outputs-specification/#31-privilege-separation-model

But in my investigations, it should be feasible to actually reuse the implementation code (mostly in Go) and this also means we reuse the exact same schema.

A huge advantage of this approach is that if e.g. my employer wanted to productize an upstream project using GH-AW today, and port them over to Fullsend, it'd be a lot more seamless if the exact same safe-outputs schema worked.

@rh-hemartin

Copy link
Copy Markdown
Member

Could you bring the topic to the contributors meeting? https://docs.google.com/document/d/106cDm4CXBg4wd2j9VpVhexHHylOLThdcpqe4p6gXIXQ

@cgwalters

Copy link
Copy Markdown
Contributor Author

Could you bring the topic to the contributors meeting? https://docs.google.com/document/d/106cDm4CXBg4wd2j9VpVhexHHylOLThdcpqe4p6gXIXQ

While I can see that document from my work machine, I often do development from a different machine that only does personal and upstream development (as is the case currently) and is not signed into work accounts.

So for reference this is now a transition point where someone outside our employer but who is interested in contributing to fullsend would get stuck.

@cgwalters

Copy link
Copy Markdown
Contributor Author

#6878 is another example of something that GH-AW is also fixing today.

@ralphbean ralphbean self-assigned this Sep 2, 2026

For GitHub-specific agent side effects, Fullsend will migrate compatible writes
from privileged post-scripts to gh-aw safe outputs, operation by operation.
Note that [gh-aw custom safe outputs exists](https://github.github.com/gh-aw/reference/custom-safe-outputs/)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hm, so - custom safe-outputs is kind of equivalent to what we have with post scripts today. The user can provide an arbitrary shell script to execute at the end of the process.

Nothing about the platform or framework ensures that the output of that is really "safe" (in both fullsend and gh-aw). It's just the flexible "escape hatch".

@ralphbean

ralphbean commented Sep 2, 2026

Copy link
Copy Markdown
Member

A thing I'm wrestling with right now, is over this:

...this also means we reuse the exact same schema.

This is both a blessing and a curse. It's a blessing insofar as github has thought this through pretty well. People will be familiar with it at some point and seeing it in fullsend harness config files will feel obvious to them - if we were to share the schema with gh-aw.

The curse might be that the schema is github-flavoured.

safe-outputs:
  create-issue:
    allowed-repos: [owner/repo-c]  # Only repo-c permitted for issues

If we want to use the safe-outputs schema as the general schema for expressing constraints on issue-creation for generic backends, could we have an agent use this to create issues in JIRA, or in service-now? "allowed-repos" doesn't make sense in those contexts.

--

It's just to say that I'm torn. If we expose safe-outputs schema to the user, we benefit from the familiarity, but we lose the control we likely need to succeed at being agnostic to the external system (be it a forge or another tracker system).

@ralphbean

Copy link
Copy Markdown
Member

That said, we could still consider using safe-outputs under the hood - by translating a fullsend-native config that looks similar to the gh-aw safe-outputs config schema down to the literal gh-aw safe-outputs config schema at runtime.

Comment on lines +43 to +45
deduplication, and policy checks. However, we will also eventually invest
in a "generic-safe-outputs" style tool that has similar opinionated verbs
for other sources such as GitLab, Forgejo and Jira.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This generic-safe-outputs may be the main thing to focus on here. i.e., to wrap gh-aw's safe-outputs in a fullsend-native version that is meant to look identical but which is forge-agnostic.

@cgwalters

Copy link
Copy Markdown
Contributor Author

If we want to use the safe-outputs schema as the general schema for expressing constraints on issue-creation for generic backends,

I think we should support explicitly prefix the entire thing with github: to start for agents which run only on GitHub.

Forge agnostic I think does really want a generic-safe-outputs tool that has its own dedicated backends for gitlab/forgejo/etc.

A problem with any abstraction layer like that is it drives to the lowest common denominator, and I don't think we want to force that. People who know they are using a specific forge should be able to do forge-native things.

This generic-safe-outputs may be the main thing to focus on here. i.e., to wrap gh-aw's safe-outputs in a fullsend-native version that is meant to look identical but which is forge-agnostic.

I'm arguing for supporting both.

BTW a previous project I generated in this space was https://github.com/LobsterTrap/service-gator and I eventually concluded it could make sense for it to grow into a generic-safe-outputs tool instead of being a MCP. At least it's not shell script...

@cgwalters

Copy link
Copy Markdown
Contributor Author

If we want to use the safe-outputs schema as the general schema for expressing constraints on issue-creation for generic backends, could we have an agent use this to create issues in JIRA,

So I was searching the GH-AW docs for the keyword "jira" and came across this:

https://github.github.com/gh-aw/reference/glossary/#jira-safe-outputs-jira-create-issue-jira-update-issue-jira-add-comment-jira-add-label

It looks like they've been building out other direct integrations. Would they accept them for GitLab or Forgejo? Would be interesting to try 😄

For GitHub-specific agent side effects, Fullsend will migrate compatible writes
from privileged post-scripts to gh-aw safe outputs, operation by operation.
Note that [gh-aw custom safe outputs exists](https://github.github.com/gh-aw/reference/custom-safe-outputs/)
as a generic escape hatch.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm on the fence about this ADR - I think its trying to go in a positive direction, but putting everything in terms of gh-aw and otherwise vague language makes it hard for me to understand what the result would look like from a Fullsend user POV.

The existence of conditional overlays in harnesses means that we can use different approaches for post run processing in different environments, so I can see us adopting a better mechanism for GH while retaining the scripts for other platforms for a while.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The existence of conditional overlays in harnesses means that we can use different approaches for post run processing in different environments

I think this gets entirely replaced with generic-safe-outputs.

@ifireball

Copy link
Copy Markdown
Member

@cgwalters my last comment is rather vague - here is something more workable - can you consider adding some overview of gh-aw safe outputs in the ADR context, enough so the reader would be agle to understand what using it in Fullsend would look and feel like?

@cgwalters

cgwalters commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

@cgwalters my last comment is rather vague - here is something more workable - can you consider adding some overview of gh-aw safe outputs in the ADR context,

I'm uncertain how I could explain it better than the docs do; and definitely not better than someone asking their own agents questions pointing them at the docs.

enough so the reader would be agle to understand what using it in Fullsend would look and feel like?

I think there's two parts to this:

  • The builtin agent implementations
  • BYO agent

(BTW, GH-AW has no "builtin agents" - really important to internalize that, and I think it's the right call. Fullsend is at least going that direction, GH-AW is already there)

Anyways most interesting is for https://fullsend.sh/docs/guides/user/bring-your-own-agent - it would be a breaking change for people doing that today.

Basically we're replacing the pre and post scripts. Or at least IMO in most cases we should replace the pre scripts with e.g. a skill the agent should execute, or a MCP tool. I mean for the triage agent is it really better to fetch all the issue content before starting the agent vs just having the agent fetch it (and btw, be able to fetch any updated content after?) Debatable.

But we're definitely replacing the post scripts with GH-AW - or perhaps per above a new "generic-safe-outputs" project that has github: as a section, and we add things for gitlab and other projects there.

Does that help?

@cgwalters

Copy link
Copy Markdown
Contributor Author

There's some interesting subtleties we could call out; for example GH-AW is in preview, and retains the capability to make breaking changes across versions - but the intended semantic is that one pins to a version.

(Heading of the "we shouldn't depend on something that can change" objection: the same is true in practice of Fullsend itself as an overall system; we're IMO pretty far from some kind of 1.0 LTS)

In practice, what would probably work is for us to pin to a version of GH-AW sources in fullsend, and then bump it whenever we're making semver bumps to other parts of fullsend.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants