{"slug": "show-hn-create-git-workflows-using-jev", "title": "Show HN: Create Git workflows using Jev", "summary": "TypeSafe AI's Jev model powers metis-workflow 0.1.0, a Python 3.10+ framework with no runtime dependencies that lets developers define Git workflows as classes with named steps, according to the project's Show HN post. The framework, which imports as metis_workflow and ships a CLI and GitHub Action, includes GitHub and Jev integrations; Jev's check() returns yes/no probabilities for a checklist and evaluate() runs Choice, Noul, and Score questions. Issue triage and PR screening are built entirely on the framework, and the archived metis-triage package now lives under legacy/.", "body_md": "`metis-workflow` is a small Python framework for workflows powered by TypeSafe AI's\nJev model. Define a workflow class, use integrations where needed, and compose\nnamed steps. Python 3.10+, no runtime dependencies.\n\n| Package | Location | Purpose | \n|---|---|---|\n| `metis-workflow` | Repository root | Framework, CLI, GitHub Action, and integrations | \n| `metis-triage` | `legacy/metis-triage/` | Archived standalone issue-triage package | \n\nThe framework imports as `metis_workflow`. Both issue triage and PR screening are\nexamples built entirely with this framework. They do not import the legacy package.\nThe current framework version is **0.1.0**.\n\nGuides: [Migration](https://github.com/Ayush0054/metis/blob/main/docs/migration.md) · [Custom workflows](https://github.com/Ayush0054/metis/blob/main/docs/custom-workflows.md).\n\nFrom this checkout:\n\n```\npython -m pip install .\n```\n\nAfter publication, the distribution can be installed with `pip install metis-workflow`.\n\n``` python\nfrom metis_workflow import Step, Workflow\nfrom metis_workflow.integrations import Jev\n\nclass SupportRouting(Workflow):\n    name = \"support-routing\"\n\n    def build_steps(self):\n        return (\n            Step(\"assess\", self.assess),\n            Step(\"route\", self.route),\n        )\n\n    def assess(self, ctx):\n        jev = ctx.integrations.setdefault(\"jev\", Jev())\n        return jev.check(ctx.event, {\n            \"billing\": \"Does this ticket concern a payment or invoice?\"\n        })\n\n    def route(self, ctx):\n        value = ctx.outputs[\"assess\"][\"billing\"]\n        return {\"queue\": \"billing\" if value >= 0.8 else\n                \"support\" if value <= 0.2 else \"manual-review\"}\n\nworkflow = SupportRouting\n```\n\nExport the class as `workflow` to run it from the CLI. In application code, use\n`SupportRouting().run(event={\"message\": \"I was charged twice\"})`.\n\n`Workflow` owns execution, skips, error handling, and the run report. Define the\norder in `build_steps()` and change behavior by overriding individual methods.\nEach step's return value is available by name in `ctx.outputs`.\n\n| Context field | Purpose | \n|---|---|\n| `event` | Input for this run | \n| `config` | Workflow defaults merged with supplied settings | \n| `integrations` | API clients shared by the steps | \n| `state` | Internal run data, omitted from the run report | \n| `outputs` | Named step results included in the run report | \n| `dry_run` | Whether write steps should suppress external changes | \n\nOverride `default_config()` and `validate_config(config)` to define and check\nsettings. Pass overrides to the constructor or `.run(config={...})`. Each run gets\nfresh state and outputs and a copy of its configuration. Supply clients with\n`SupportRouting(integrations={\"jev\": Jev(...)})` or `.run(integrations={...})`.\n\nUse `Step(\"notify\", self.notify, when=lambda ctx: ...)` for conditional steps.\nCall `ctx.skip(\"reason\")` to stop the workflow normally. Errors stop subsequent\nsteps. Write steps must honor `ctx.dry_run`; return only data suitable for the run\nreport. Override `matches(event, event_name=None)` to control event dispatch.\nWorkflows run sequentially in one process; scheduling comes from the caller or\nGitHub Actions.\n\n`src/metis_workflow/integrations/` contains the shared clients:\n\n- `GitHub(repository, token=None, dry_run=False)` reads repository API endpoints,\nfollows paginated lists, and supports explicit writes.\n- `Jev(api_key=None, model=None)` supplies typed judgments.`check(state, criteria)` returns yes/no probabilities for a checklist.`evaluate(state, questions)` runs\nChoice, Noul, and Score questions together and validates the returned answers.\nQuestion and answer shapes follow the[TypeSafe API](https://docs.typesafe.ai/api) .\n\nGitHub credentials default to `GITHUB_TOKEN`. Jev credentials default to\n`TYPESAFE_API_KEY`, and the model defaults to `TYPESAFE_DEFAULT_MODEL` or `jev-latest`.\nThe workflow owns thresholds, policies, and actions; integrations own API calls.\n\n```\nsrc/metis_workflow/\n  workflow.py             Workflow, Step, and Context\n  runner.py               Event dispatch\n  integrations/\n    github.py             GitHub API client\n    jev.py                Typed Jev judgments\nexamples/\n  issue_triage.py         IssueTriage(Workflow)\n  issue_triage.json       Label names and triage thresholds\n  pr_screening.py         PRScreening(Workflow)\n  pr_screening.json       PR criteria and screening policy\n  support_routing.py      SupportRouting(Workflow)\nlegacy/metis-triage/       Independent archived package\n```\n\nCopy an example and its companion JSON to customize it. Both GitHub examples read defaults from the JSON next to their Python file. They use the same public framework and integrations available to any user workflow.\n\n| Example | Steps | Result | \n|---|---|---|\n| Issue triage | load → classify → label → reply | Labels issues and requests missing bug details | \n| PR screening | load → evidence → judge → apply | Screens external contributions and closes clear failures | \n| Support routing | assess → route | Chooses a support queue and priority | \n\nIssue triage classifies new issues as bug, feature, documentation, question, or\nother. It applies existing labels only after configured confidence and probability\nthresholds pass. For clear bugs, it posts a fixed template listing missing\nreproduction, behavior, or environment details. It skips uncertain results,\nbot-authored or oversized issues, changed text, conflicting category labels,\nprevious Metis replies, and conversations a person has already joined. It does not\ncreate labels or close issues. Default label names are `bug`, `enhancement`,\n`documentation`, and `question`; configure names that exist in your repository.\n\nPR screening exempts the repository owner and owning organization's members, bots, drafts, and configured author exemptions. It reads the title, body, patches, repository description, and README at the trusted base commit. The default checks are relevance, a concrete useful change, and absence of promotional spam. No linked issue is required; small fixes and documentation improvements count.\n\nPassing and uncertain PRs stay open. A criterion probability at or below `0.05`\nallows closure; all probabilities at least `0.8` count as passing. Missing,\nbinary, or incomplete patches and oversized PRs need manual review. These are\ninitial policy thresholds, not evaluated accuracy guarantees. The workflow\nrechecks PR state before writing, posts a configured explanation, and closes\nclear failures. There remains a small race between the final read and GitHub's\nclose request. Reopened PRs are screened again; use an author exemption to\nexclude a contributor from future screening.\n\n```\nmetis-workflow run --workflow-file examples/support_routing.py --event ticket.json\nmetis-workflow run --workflow-file examples/issue_triage.py --event issue-event.json --dry-run\nmetis-workflow run --workflow-file examples/pr_screening.py --event pr-event.json --dry-run\n```\n\n`--event` supplies a JSON input object. For a single class file, `--config path.json`\noverrides its defaults. A dry run still reads GitHub and calls Jev; the examples\nsuppress writes when `dry_run` is true. Loading a workflow file executes trusted\nlocal Python.\n\nFor several workflows, create a manifest such as `.github/metis-workflows.json`:\n\n```\n{\n  \"version\": 1,\n  \"workflows\": [\n    {\"name\": \"issue-triage\", \"file\": \"../examples/issue_triage.py\"},\n    {\n      \"name\": \"pr-screening\",\n      \"file\": \"../examples/pr_screening.py\",\n      \"config\": {\"repository_context\": \"We accept bug fixes, examples, and docs improvements.\"}\n    }\n  ]\n}\n```\n\nEntries contain a unique `name`, a `file` relative to the manifest, and optional\n`enabled` and `config` fields. Settings override top-level defaults; a `criteria`\nobject replaces the complete checklist. All workflows use this same file-based\nregistration; the framework has no built-in use cases or legacy adapters.\n\n```\nmetis-workflow list --manifest .github/metis-workflows.json\nmetis-workflow run --manifest .github/metis-workflows.json --workflow issue-triage --event issue-event.json\n```\n\nThe dispatcher calls each class's `matches()` method. `python -m metis_workflow`\nuses the same CLI.\n\nCopy the examples, companion JSON files, and manifest into your repository. Add\nthe following workflow on the default branch and configure `TYPESAFE_API_KEY` as a\nrepository secret. Pin a published commit containing this framework for reproducible\nuse; `main` is the development reference.\n\n```\nname: Metis workflows\non:\n  issues:\n    types: [opened]\n  pull_request_target:\n    types: [opened, reopened, synchronize, edited, ready_for_review]\n\npermissions:\n  contents: read\n  issues: write\n  pull-requests: write\n\nconcurrency:\n  group: metis-${{ github.repository }}-${{ github.event.issue.number || github.event.pull_request.number }}\n  cancel-in-progress: false\n\njobs:\n  run:\n    runs-on: ubuntu-latest\n    timeout-minutes: 5\n    steps:\n      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2\n        with:\n          ref: ${{ github.event.pull_request.base.sha || github.sha }}\n          persist-credentials: false\n      - uses: Ayush0054/metis@main\n        with:\n          manifest-path: .github/metis-workflows.json\n          typesafe-api-key: ${{ secrets.TYPESAFE_API_KEY }}\n```\n\nUse `workflow` to select a name from the manifest. To run one class directly, set\n`workflow-file: examples/issue_triage.py` and optional `config-path` instead of\n`manifest-path`. `dry-run: 'true'` asks the workflow to evaluate without writes.\nThe optional `github-token` and `model` inputs replace the default GitHub token\nand Jev model. A write error can leave a partial action; inspect or rerun the job.\n\nOnly trusted base code and configuration should execute in `pull_request_target`.\nPR head code must never be checked out or run in this privileged job. See\n[GitHub's trigger documentation](https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#pull_request_target).\nIssue text, PR text, and patches are sent to TypeSafe for evaluation.\n\n[`legacy/metis-triage`](https://github.com/Ayush0054/metis/blob/main/legacy/metis-triage/README.md) retains the original package\nat version `0.1.0`, with its own metadata, source, README, and license. It can be\ninstalled independently. It has no dependency on the new framework, and the new\nframework and examples have no dependency on it. New work belongs in\n`metis-workflow` and the examples.\n\n`.github/workflows/publish.yml` builds only the root `metis-workflow` distribution\nand publishes through PyPI Trusted Publishing. Configure the publisher for project\n`metis-workflow`, owner `Ayush0054`, repository `metis`, workflow `publish.yml`, and\nenvironment `pypi-workflow`. A release tag must match the root package version,\ncurrently `v0.1.0`. The legacy package has no automated publication in this workflow.\n\nThe class API draws on [Temporal workflow classes](https://docs.temporal.io/develop/python/workflows/basics),\nstep composition on [Agno workflows](https://docs.agno.com/workflows/overview), and\nexplicit execution state on [Prefect flows](https://docs.prefect.io/v3/concepts/flows).\n\n[MIT](https://github.com/Ayush0054/metis/blob/main/LICENSE) © 2026 Ayush Jha.", "url": "https://wpnews.pro/news/show-hn-create-git-workflows-using-jev", "canonical_source": "https://github.com/Ayush0054/metis", "published_at": "2026-10-04 14:26:53+00:00", "updated_at": "2026-10-04 14:42:26.769148+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-tools", "artificial-intelligence"], "entities": ["TypeSafe AI", "Jev", "metis-workflow", "metis-triage", "GitHub", "Python", "Ayush0054"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/show-hn-create-git-workflows-using-jev", "markdown": "https://wpnews.pro/news/show-hn-create-git-workflows-using-jev.md", "text": "https://wpnews.pro/news/show-hn-create-git-workflows-using-jev.txt", "jsonld": "https://wpnews.pro/news/show-hn-create-git-workflows-using-jev.jsonld"}}