Repository navigation
Expand file tree
/
Copy pathpyproject.toml
More file actions
145 lines (135 loc) · 6.48 KB
/
Copy pathpyproject.toml
File metadata and controls
145 lines (135 loc) · 6.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# Packaging config for PyPI.
#
# A fresh `pip install qikly` is runnable on its own: `qikly --init` creates
# the project layout and a starter task in whatever directory you are standing
# in, and `qikly --scaffold <file.py>` writes a task for code that already
# exists. The bundled tasks, agent definitions, fixtures and default settings
# ship inside the package (see paths.py), so an install and a git clone run
# against the same defaults and produce the same outputs.
[build-system]
requires = ["setuptools>=68"]
build-backend = "setuptools.build_meta"
[project]
name = "qikly"
version = "0.6.1"
description = "Generates a test suite from acceptance criteria, then converges code against it with an agent that never sees those criteria."
readme = "README.md"
requires-python = ">=3.10"
license = "Apache-2.0"
license-files = ["LICENSE"]
authors = [{ name = "Gal Arav" }]
keywords = ["llm", "agent", "testing", "qa", "acceptance-criteria", "code-generation", "mcp", "model-context-protocol"]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Software Development :: Quality Assurance",
"Topic :: Software Development :: Testing",
]
# Mirrors requirements.txt. Kept in sync by hand rather than read from that
# file at build time: dynamic dependencies make the built metadata depend on
# files that aren't in the sdist, which is a classic source of "works from a
# clone, broken from PyPI".
# Upper bounds on every one, and the reason is on record rather than
# theoretical: anthropic 1.x removed `temperature` from Messages.create(), so
# a provider that had worked stopped working on a major bump nobody here made.
# A floor alone lets that happen silently to a user on a fresh install.
#
# These are deliberately wide. The bound exists to stop a major version
# arriving unannounced, not to pin a patch release, and raising one after
# testing is a two-line change.
dependencies = [
"PyYAML>=6.0,<7",
"google-genai>=2.0,<3",
"pytest>=8.0,<10",
"rich>=13.0,<16",
]
# Not installed by default: pick the one you use. Only Gemini is a hard
# dependency, and tests/test_provider_signatures.py checks whichever of these
# happens to be present against what the code sends it.
[project.optional-dependencies]
openai = ["openai>=1.0,<4"]
anthropic = ["anthropic>=0.30,<2"]
all-providers = ["openai>=1.0,<4", "anthropic>=0.30,<2"]
# The MCP server. Optional because it is a way in, not the tool: everything it
# exposes works without it, and every test in this repository runs without it.
mcp = ["mcp>=2.0,<3"]
[project.urls]
Homepage = "https://test.qikly.com/"
Documentation = "https://test.qikly.com/"
Repository = "https://github.com/gal-a/qikly"
Issues = "https://github.com/gal-a/qikly/issues"
Changelog = "https://github.com/gal-a/qikly/blob/main/CHANGELOG.md"
[project.scripts]
qikly = "qikly.cli:main"
qikly-all = "qikly.orchestrator.run_all:main"
qikly-report = "qikly.orchestrator.reports.report:main"
qikly-metrics = "qikly.orchestrator.reports.metrics_report:main"
qikly-diff-criteria = "qikly.orchestrator.tuning.diff_acceptance_criteria:main"
qikly-mcp = "qikly.mcp_server:main"
[tool.setuptools]
# src layout: the package lives in src/, not at the repo root. That keeps the
# project's own inputs/, inputs_private/, and outputs/ from sitting next to
# importable code, and it makes it impossible to import qikly from the
# source tree by accident when you meant to exercise the installed copy --
# which is exactly the mistake that hides a broken wheel until after upload.
package-dir = { "" = "src" }
# Explicit, not auto-discovered: auto-discovery would sweep in `outputs` and
# any `inputs_private` the developer has locally as if they were packages.
packages = [
"qikly",
"qikly.agent_api",
"qikly.agent_api.code_loader",
"qikly.agent_api.prompts",
"qikly.agent_api.providers",
"qikly.agent_tools",
"qikly.orchestrator",
"qikly.orchestrator.reports",
"qikly.orchestrator.tuning",
]
# No py-modules. The root run.py is a clone convenience only -- installing a
# top-level module named `run` would reintroduce exactly the collision that
# nesting everything under qikly/ removes.
[tool.setuptools.package-data]
# The bundled defaults ship in the wheel. This is what makes a fresh
# `pip install` immediately runnable: the example tasks, agent definitions,
# sample data, and default settings.yaml are all present,
# so a new user's first run produces the same outputs as a clone's.
# Their own specs go in inputs_private/ in their project directory, which is
# never packaged -- see qikly/paths.py.
"qikly" = [
"inputs_public/config/*.yaml",
"inputs_public/config/tasks/*.yaml",
"inputs_public/reference/*/*.py",
"inputs_public/agent_defs/*.md",
# The agent Skill, so `qikly --install-skill` works from a wheel and not
# only from a clone. A Skill is a folder an agent reads, and its two
# bundled references are complete copies of the docs pages, asserted
# identical by tests/test_skill_bundle.py, so it works with no network.
"skills/*/*.md",
"skills/*/references/*.md",
"inputs_public/data/**/*",
# The worked scaffold example, laid out the way a real project is so a
# reader sees the right shape. Not a bundled task: it lives under
# examples/ so it stays out of the task list and out of --validate.
"inputs_public/examples/**/*",
# The MCP server's icon. Shipped rather than read out of docs/, which is
# not in the wheel, and embedded as a data URI at runtime so no host has
# to resolve a path on the reader's filesystem.
"assets/*.svg",
]
[tool.pytest.ini_options]
# tests/ only. Without this, a bare `pytest` also collects outputs/tests/,
# which holds generated suites from previous runs: they import task modules
# that may not exist, and their failures say nothing about this package.
testpaths = ["tests"]
# No -q here. A project addopts of "-q" combines with a "-q" the user types
# into -qq, and -qq suppresses the "N passed" summary line entirely: the run
# then reports a bare "100%" and says nothing about how many tests ran or
# whether any failed. That is not hypothetical. The same collision inside this
# tool's own pytest calls silently zeroed an entire experiment's measurement,
# which is why those calls now pass "-o addopts=". Anyone who wants quiet
# output can still type -q and get the summary with it.