gfly 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gfly-0.1.0/.editorconfig +18 -0
- gfly-0.1.0/.github/CODEOWNERS +7 -0
- gfly-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +61 -0
- gfly-0.1.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
- gfly-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +38 -0
- gfly-0.1.0/.github/PUBLISH_CHECKLIST.md +47 -0
- gfly-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +15 -0
- gfly-0.1.0/.github/workflows/ci.yml +25 -0
- gfly-0.1.0/.github/workflows/release.yml +53 -0
- gfly-0.1.0/.gitignore +17 -0
- gfly-0.1.0/AGENTS.md +41 -0
- gfly-0.1.0/CHANGELOG.md +28 -0
- gfly-0.1.0/CITATION.cff +22 -0
- gfly-0.1.0/CODE_OF_CONDUCT.md +99 -0
- gfly-0.1.0/CONTRIBUTING.md +47 -0
- gfly-0.1.0/LICENSE-APACHE +202 -0
- gfly-0.1.0/LICENSE-MIT +21 -0
- gfly-0.1.0/PKG-INFO +230 -0
- gfly-0.1.0/README.md +207 -0
- gfly-0.1.0/SECURITY.md +46 -0
- gfly-0.1.0/SUPPORT.md +23 -0
- gfly-0.1.0/demo/gfly.gif +0 -0
- gfly-0.1.0/demo/gfly.tape +45 -0
- gfly-0.1.0/llms.txt +30 -0
- gfly-0.1.0/pyproject.toml +40 -0
- gfly-0.1.0/site/.gitignore +1 -0
- gfly-0.1.0/site/gfly.gif +0 -0
- gfly-0.1.0/site/index.html +244 -0
- gfly-0.1.0/spec.md +230 -0
- gfly-0.1.0/src/gfly/SKILL.md +74 -0
- gfly-0.1.0/src/gfly/__init__.py +19 -0
- gfly-0.1.0/src/gfly/__main__.py +6 -0
- gfly-0.1.0/src/gfly/airports.py +45 -0
- gfly-0.1.0/src/gfly/auth.py +134 -0
- gfly-0.1.0/src/gfly/backend.py +321 -0
- gfly-0.1.0/src/gfly/cli.py +629 -0
- gfly-0.1.0/src/gfly/errors.py +127 -0
- gfly-0.1.0/src/gfly/output.py +135 -0
- gfly-0.1.0/src/gfly/skill.py +9 -0
- gfly-0.1.0/src/gfly/throttle.py +144 -0
- gfly-0.1.0/tests/conftest.py +80 -0
- gfly-0.1.0/tests/test_cli.py +228 -0
- gfly-0.1.0/tests/test_schema_snapshot.py +42 -0
- gfly-0.1.0/uv.lock +554 -0
gfly-0.1.0/.editorconfig
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
root = true
|
|
2
|
+
|
|
3
|
+
[*]
|
|
4
|
+
charset = utf-8
|
|
5
|
+
end_of_line = lf
|
|
6
|
+
insert_final_newline = true
|
|
7
|
+
trim_trailing_whitespace = true
|
|
8
|
+
indent_style = space
|
|
9
|
+
indent_size = 4
|
|
10
|
+
|
|
11
|
+
[*.{md,yml,yaml,json,toml,tape}]
|
|
12
|
+
indent_size = 2
|
|
13
|
+
|
|
14
|
+
[*.md]
|
|
15
|
+
trim_trailing_whitespace = false
|
|
16
|
+
|
|
17
|
+
[Makefile]
|
|
18
|
+
indent_style = tab
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Something in gfly behaves incorrectly.
|
|
3
|
+
labels: ["bug"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Thanks for reporting! For **security** issues do NOT use this form — see SECURITY.md.
|
|
9
|
+
Please **redact any secrets** (SerpApi keys, cookies) before pasting output.
|
|
10
|
+
- type: input
|
|
11
|
+
id: version
|
|
12
|
+
attributes:
|
|
13
|
+
label: gfly version
|
|
14
|
+
description: Output of `gfly --version`.
|
|
15
|
+
placeholder: "0.1.0"
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
- type: dropdown
|
|
19
|
+
id: backend
|
|
20
|
+
attributes:
|
|
21
|
+
label: Backend
|
|
22
|
+
options: ["google (default)", "serpapi"]
|
|
23
|
+
validations:
|
|
24
|
+
required: true
|
|
25
|
+
- type: input
|
|
26
|
+
id: os
|
|
27
|
+
attributes:
|
|
28
|
+
label: OS / Python
|
|
29
|
+
placeholder: "Ubuntu 24.04 / Python 3.12 (uv)"
|
|
30
|
+
validations:
|
|
31
|
+
required: true
|
|
32
|
+
- type: textarea
|
|
33
|
+
id: command
|
|
34
|
+
attributes:
|
|
35
|
+
label: Command
|
|
36
|
+
description: The exact command you ran (redact secrets).
|
|
37
|
+
render: shell
|
|
38
|
+
validations:
|
|
39
|
+
required: true
|
|
40
|
+
- type: textarea
|
|
41
|
+
id: expected
|
|
42
|
+
attributes:
|
|
43
|
+
label: What you expected vs. what happened
|
|
44
|
+
validations:
|
|
45
|
+
required: true
|
|
46
|
+
- type: textarea
|
|
47
|
+
id: error
|
|
48
|
+
attributes:
|
|
49
|
+
label: Structured error / exit code
|
|
50
|
+
description: Paste the JSON error from stderr and the exit code (`echo $?`).
|
|
51
|
+
render: json
|
|
52
|
+
validations:
|
|
53
|
+
required: false
|
|
54
|
+
- type: textarea
|
|
55
|
+
id: schema
|
|
56
|
+
attributes:
|
|
57
|
+
label: gfly doctor output
|
|
58
|
+
description: Output of `gfly doctor --json` (secrets are redacted automatically).
|
|
59
|
+
render: json
|
|
60
|
+
validations:
|
|
61
|
+
required: false
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
blank_issues_enabled: false
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: 🔒 Security vulnerability
|
|
4
|
+
url: https://github.com/rnwolfe/gfly/security/advisories/new
|
|
5
|
+
about: Report security issues privately — never via a public issue. See SECURITY.md.
|
|
6
|
+
- name: 💬 Questions & ideas
|
|
7
|
+
url: https://github.com/rnwolfe/gfly/discussions
|
|
8
|
+
about: Ask questions, share recipes, or discuss before filing a feature request.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest a capability or improvement for gfly.
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
gfly is **read-only by design** (it searches; it does not book) and **agent-first**
|
|
9
|
+
(stable JSON, structured errors, bounded output). Requests that respect those
|
|
10
|
+
constraints are most likely to land.
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: problem
|
|
13
|
+
attributes:
|
|
14
|
+
label: Problem / use case
|
|
15
|
+
description: What are you trying to do, and what's blocking you today?
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
- type: textarea
|
|
19
|
+
id: proposal
|
|
20
|
+
attributes:
|
|
21
|
+
label: Proposed solution
|
|
22
|
+
description: Command surface, flags, and the output fields you'd expect.
|
|
23
|
+
validations:
|
|
24
|
+
required: true
|
|
25
|
+
- type: dropdown
|
|
26
|
+
id: backend
|
|
27
|
+
attributes:
|
|
28
|
+
label: Which backend(s)?
|
|
29
|
+
multiple: true
|
|
30
|
+
options: ["google", "serpapi", "both / new backend"]
|
|
31
|
+
validations:
|
|
32
|
+
required: false
|
|
33
|
+
- type: textarea
|
|
34
|
+
id: alternatives
|
|
35
|
+
attributes:
|
|
36
|
+
label: Alternatives considered
|
|
37
|
+
validations:
|
|
38
|
+
required: false
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Publish checklist (manual operator steps)
|
|
2
|
+
|
|
3
|
+
The repo, README, demo, hygiene, landing page, and release pipeline are ready. These steps require
|
|
4
|
+
your credentials / a browser and can't be automated from here.
|
|
5
|
+
|
|
6
|
+
## 1. Create the GitHub repo & push
|
|
7
|
+
```bash
|
|
8
|
+
gh repo create rnwolfe/gfly --public --source=. --remote=origin --push \
|
|
9
|
+
--description "Google Flights for agents — a read-only, JSON-first flight-search CLI an LLM can drive (no API key)."
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## 2. Repo settings (Settings → …)
|
|
13
|
+
- **Topics** (≤20, lowercase-hyphen): `cli` `google-flights` `flight-search` `agent` `llm`
|
|
14
|
+
`agentic` `python` `uv` `travel` `json` `read-only` `serpapi`.
|
|
15
|
+
- **About → website**: the docs/landing URL once hosted.
|
|
16
|
+
- **Social preview**: upload a 1280×640 card (reuse the split-flap board aesthetic from `site/`).
|
|
17
|
+
- **Security → enable Private Vulnerability Reporting** (required for SECURITY.md's flow).
|
|
18
|
+
- **Discussions**: enable (SUPPORT.md and the issue `config.yml` link to it).
|
|
19
|
+
- **Branches → protect `main`**: require PR + status checks (`ci`) + **require review from Code Owners**.
|
|
20
|
+
|
|
21
|
+
## 3. PyPI Trusted Publishing (no stored secrets)
|
|
22
|
+
- Register the project on PyPI, then add a **Trusted Publisher**: owner `rnwolfe`, repo `gfly`,
|
|
23
|
+
workflow `release.yml`, environment `pypi`. Must match the workflow exactly.
|
|
24
|
+
- Create a repo **Environment** named `pypi`.
|
|
25
|
+
|
|
26
|
+
## 4. First release (delegate to the `release` skill)
|
|
27
|
+
- Run `/release` to: bump version from Conventional Commits, finalize `CHANGELOG.md`, and create an
|
|
28
|
+
**SSH-signed annotated tag** (→ "Verified" badge). Push the tag → `release.yml` builds, attests
|
|
29
|
+
provenance, publishes to PyPI (OIDC), and creates the GitHub Release with `SHA256SUMS`.
|
|
30
|
+
- Verify: `gh attestation verify <wheel> -R rnwolfe/gfly`.
|
|
31
|
+
|
|
32
|
+
## 5. Docs site (delegate)
|
|
33
|
+
- `/starlight-docs` — scaffold the Astro Starlight site (Diátaxis IA, `llms.txt`, Pagefind search,
|
|
34
|
+
GitHub Pages deploy + base-path config, AGENTS.md freshness wiring).
|
|
35
|
+
- `/harvest-docs` — fill it from the code (multi-agent: scavenge → IA → per-page writers → reviewers).
|
|
36
|
+
- Auto-generate the Reference quadrant from Click; add the CI freshness gate (regenerate + `git diff --exit-code`).
|
|
37
|
+
|
|
38
|
+
## 6. Host the landing page
|
|
39
|
+
- `site/index.html` is self-contained (only `gfly.gif` alongside it). Serve via GitHub Pages, or
|
|
40
|
+
`expose` for a quick LAN review. Optionally reserve `gfly.sh`.
|
|
41
|
+
|
|
42
|
+
## 7. Discoverability (after a tag + >20 stars where required)
|
|
43
|
+
- **awesome-cli-apps** (one app/PR, format `[gfly](url) - Description.`).
|
|
44
|
+
- **awesome-agent-clis** (ComposioHQ) — folder + the bundled `SKILL.md`.
|
|
45
|
+
- **clis.dev** `/submit`; terminaltrove.com.
|
|
46
|
+
- Launch: **Show HN** (`Show HN: gfly – Google Flights for agents (no API key)`, link the repo, be
|
|
47
|
+
present the first 30–60 min); r/commandline; Product Hunt 12:01 PT.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!-- Title must follow Conventional Commits, e.g. `feat: add --max-price filter` -->
|
|
2
|
+
|
|
3
|
+
## What & why
|
|
4
|
+
|
|
5
|
+
<!-- What does this change and why? Link any issue: Closes #123 -->
|
|
6
|
+
|
|
7
|
+
## Checklist
|
|
8
|
+
|
|
9
|
+
- [ ] Title uses [Conventional Commits](https://www.conventionalcommits.org/) (`feat:` / `fix:` / `docs:` / …)
|
|
10
|
+
- [ ] `uv run pytest -q` passes locally
|
|
11
|
+
- [ ] Output contract respected: **append-only** fields; stdout=data / stderr=chatter
|
|
12
|
+
- [ ] If the agent-facing schema changed: `SCHEMA_VERSION` bumped + `tests/test_schema_snapshot.py` updated
|
|
13
|
+
- [ ] No secrets via argv; read-only invariant preserved (no new mutations)
|
|
14
|
+
- [ ] `CHANGELOG.md` (Unreleased) and docs / `SKILL.md` updated if behavior changed
|
|
15
|
+
- [ ] Commits signed off (`git commit -s`, DCO)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
matrix:
|
|
13
|
+
python-version: ["3.10", "3.12"]
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- name: Install uv
|
|
17
|
+
uses: astral-sh/setup-uv@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: ${{ matrix.python-version }}
|
|
20
|
+
- name: Sync
|
|
21
|
+
run: uv sync --extra dev
|
|
22
|
+
- name: Test (contract gate)
|
|
23
|
+
run: uv run pytest -q
|
|
24
|
+
- name: Schema smoke
|
|
25
|
+
run: uv run gfly schema > /dev/null
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
|
|
3
|
+
# Tag-driven release: build → checksums → build-provenance attestation (SLSA L2) →
|
|
4
|
+
# PyPI Trusted Publishing (OIDC) → GitHub Release with artifacts + SHA256SUMS.
|
|
5
|
+
# Prereqs (one-time, manual): configure PyPI Trusted Publishing for owner=rnwolfe,
|
|
6
|
+
# repo=gfly, workflow=release.yml, environment=pypi.
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
push:
|
|
10
|
+
tags: ["v*"]
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: write # create the GitHub Release
|
|
14
|
+
id-token: write # PyPI OIDC + provenance signing (no stored secrets)
|
|
15
|
+
attestations: write # actions/attest-build-provenance
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
release:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
environment: pypi
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
|
+
with:
|
|
24
|
+
fetch-depth: 0
|
|
25
|
+
|
|
26
|
+
- name: Install uv
|
|
27
|
+
uses: astral-sh/setup-uv@v5
|
|
28
|
+
|
|
29
|
+
- name: Build sdist + wheel
|
|
30
|
+
run: uv build
|
|
31
|
+
|
|
32
|
+
- name: Generate checksums
|
|
33
|
+
run: cd dist && sha256sum * > SHA256SUMS && cat SHA256SUMS
|
|
34
|
+
|
|
35
|
+
# SLSA L2 build provenance. Skipped on private user-owned repos (the action
|
|
36
|
+
# fails there and would block the publish).
|
|
37
|
+
- name: Attest build provenance
|
|
38
|
+
if: ${{ !github.event.repository.private }}
|
|
39
|
+
uses: actions/attest-build-provenance@v1
|
|
40
|
+
with:
|
|
41
|
+
subject-path: "dist/*.whl, dist/*.tar.gz"
|
|
42
|
+
|
|
43
|
+
- name: Publish to PyPI (Trusted Publishing / OIDC)
|
|
44
|
+
run: uv publish
|
|
45
|
+
|
|
46
|
+
- name: Create GitHub Release
|
|
47
|
+
env:
|
|
48
|
+
GH_TOKEN: ${{ github.token }}
|
|
49
|
+
run: |
|
|
50
|
+
gh release create "${GITHUB_REF_NAME}" \
|
|
51
|
+
dist/*.whl dist/*.tar.gz dist/SHA256SUMS \
|
|
52
|
+
--title "${GITHUB_REF_NAME}" \
|
|
53
|
+
--notes "See [CHANGELOG.md](https://github.com/rnwolfe/gfly/blob/main/CHANGELOG.md). Verify provenance: \`gh attestation verify <artifact> -R rnwolfe/gfly\`."
|
gfly-0.1.0/.gitignore
ADDED
gfly-0.1.0/AGENTS.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# AGENTS.md — gfly
|
|
2
|
+
|
|
3
|
+
Conventions for agents editing this repo. (End users driving the CLI want `gfly agent` /
|
|
4
|
+
`src/gfly/SKILL.md` instead.)
|
|
5
|
+
|
|
6
|
+
## What this is
|
|
7
|
+
`gfly` is an agent-first, **read-only** CLI for searching Google Flights. Scaffolded by
|
|
8
|
+
agent-cli-factory from the Python (Click) template. `spec.md` is the single source of truth.
|
|
9
|
+
|
|
10
|
+
## Build / test / run
|
|
11
|
+
```bash
|
|
12
|
+
uv sync --extra dev # install (uv-managed; Python >=3.10)
|
|
13
|
+
uv run pytest -q # contract + behavior tests (must stay green)
|
|
14
|
+
uv run gfly schema # machine-readable command tree
|
|
15
|
+
uv run gfly search JFK LHR --depart 2026-08-01 --json
|
|
16
|
+
python -m gfly --help # module entry also works
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Layout
|
|
20
|
+
- `src/gfly/cli.py` — Click grammar, `Runtime`, global-flag merge, exit-code mapping. **Contract
|
|
21
|
+
surface; edit deliberately.** Global flags must work in any position (the `_resolve` walk).
|
|
22
|
+
- `src/gfly/output.py` — stdout=data / stderr=chatter, `--format`, `--select`, `--limit`. **Do not edit.**
|
|
23
|
+
- `src/gfly/errors.py` — exit-code table + structured `AppError` (incl. `BLOCKED` 20, `SCHEMA_DRIFT` 21).
|
|
24
|
+
- `src/gfly/throttle.py` — persistent cross-process politeness/circuit-breaker (real infra).
|
|
25
|
+
- `src/gfly/backend.py` — **PLACEHOLDER** stub data. `cli-implement` replaces with fast-flights
|
|
26
|
+
(google) + SerpApi (serpapi), behind the same normalized shapes.
|
|
27
|
+
- `src/gfly/auth.py` — **PLACEHOLDER** credential resolution (env only today; keyring later).
|
|
28
|
+
- `src/gfly/SKILL.md` — embedded; printed by `gfly agent`. Regenerate when the surface changes.
|
|
29
|
+
|
|
30
|
+
## Rules
|
|
31
|
+
- **Read-only tool.** No command mutates. The `--allow-mutations` gate + `Runtime.guard` are kept
|
|
32
|
+
for contract uniformity but unused; don't add mutations without revisiting `spec.md`.
|
|
33
|
+
- **Output contract is append-only** (contract §10). New fields OK; never rename/remove. Bump
|
|
34
|
+
`SCHEMA_VERSION` (in `backend.py`) on any breaking shape change and update the snapshot test.
|
|
35
|
+
- **Secrets via stdin/env, never argv** (contract §7).
|
|
36
|
+
- **Heavy imports stay lazy** — inside backend functions, never at module top (keeps `--help`/`schema` fast).
|
|
37
|
+
- Keep `uv run pytest -q` green before every commit; the `schema` test is the contract gate.
|
|
38
|
+
|
|
39
|
+
## Handoff state
|
|
40
|
+
This is a **scaffold**: it compiles, runs on stub data, and passes contract tests. Next stage is
|
|
41
|
+
`cli-implement` — wire the real engines + auth, replacing `backend.py` / `auth.py`.
|
gfly-0.1.0/CHANGELOG.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - 2026-06-23
|
|
11
|
+
|
|
12
|
+
First public release.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- `search` (one-way / round-trip), `dates` (price calendar), `multi` (multi-city), and
|
|
16
|
+
`airports search` (offline IATA resolution) commands.
|
|
17
|
+
- Swappable backends: `google` (reverse-engineered, zero-auth, default) and `serpapi` (live JSON, keyed).
|
|
18
|
+
- Agent-CLI contract: stable versioned JSON envelope (`schemaVersion`), `schema` self-description,
|
|
19
|
+
embedded `agent` SKILL.md, `--select`/`--limit`/`--offset` token bounding, `--format json|plain|tsv`.
|
|
20
|
+
- Semantic exit codes incl. `BLOCKED` (20) and `SCHEMA_DRIFT` (21); structured errors with
|
|
21
|
+
`retryAfterSeconds` on throttle/block.
|
|
22
|
+
- Persistent, cross-process politeness throttle (min-interval + circuit breaker) with fail-fast
|
|
23
|
+
default and `--wait` opt-in.
|
|
24
|
+
- `auth login|status|logout` (OS keyring + `0600` file fallback, stdin-only secrets); real `doctor`.
|
|
25
|
+
- Prompt-injection hardening: third-party text sanitized and fenced as untrusted by default.
|
|
26
|
+
|
|
27
|
+
[Unreleased]: https://github.com/rnwolfe/gfly/compare/v0.1.0...HEAD
|
|
28
|
+
[0.1.0]: https://github.com/rnwolfe/gfly/releases/tag/v0.1.0
|
gfly-0.1.0/CITATION.cff
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use gfly, please cite it using these metadata."
|
|
3
|
+
title: "gfly: an agent-first, read-only Google Flights CLI"
|
|
4
|
+
abstract: >-
|
|
5
|
+
gfly is a read-only, JSON-first command-line tool for searching Google Flights,
|
|
6
|
+
engineered to be driven by LLM agents: stable versioned output schema, machine-readable
|
|
7
|
+
self-description, semantic exit codes, token-bounded output, a persistent politeness
|
|
8
|
+
throttle, and a swappable backend (reverse-engineered Google Flights or SerpApi).
|
|
9
|
+
type: software
|
|
10
|
+
authors:
|
|
11
|
+
- family-names: Wolfe
|
|
12
|
+
given-names: Ryan
|
|
13
|
+
license: "MIT OR Apache-2.0"
|
|
14
|
+
repository-code: "https://github.com/rnwolfe/gfly"
|
|
15
|
+
url: "https://github.com/rnwolfe/gfly"
|
|
16
|
+
keywords:
|
|
17
|
+
- google-flights
|
|
18
|
+
- cli
|
|
19
|
+
- agent
|
|
20
|
+
- llm
|
|
21
|
+
- flight-search
|
|
22
|
+
- travel
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our community a
|
|
6
|
+
harassment-free experience for everyone, regardless of age, body size, visible or invisible
|
|
7
|
+
disability, ethnicity, sex characteristics, gender identity and expression, level of experience,
|
|
8
|
+
education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or
|
|
9
|
+
sexual identity and orientation.
|
|
10
|
+
|
|
11
|
+
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and
|
|
12
|
+
healthy community.
|
|
13
|
+
|
|
14
|
+
## Our Standards
|
|
15
|
+
|
|
16
|
+
Examples of behavior that contributes to a positive environment for our community include:
|
|
17
|
+
|
|
18
|
+
* Demonstrating empathy and kindness toward other people
|
|
19
|
+
* Being respectful of differing opinions, viewpoints, and experiences
|
|
20
|
+
* Giving and gracefully accepting constructive feedback
|
|
21
|
+
* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the
|
|
22
|
+
experience
|
|
23
|
+
* Focusing on what is best not just for us as individuals, but for the overall community
|
|
24
|
+
|
|
25
|
+
Examples of unacceptable behavior include:
|
|
26
|
+
|
|
27
|
+
* The use of sexualized language or imagery, and sexual attention or advances of any kind
|
|
28
|
+
* Trolling, insulting or derogatory comments, and personal or political attacks
|
|
29
|
+
* Public or private harassment
|
|
30
|
+
* Publishing others' private information, such as a physical or email address, without their explicit
|
|
31
|
+
permission
|
|
32
|
+
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
|
33
|
+
|
|
34
|
+
## Enforcement Responsibilities
|
|
35
|
+
|
|
36
|
+
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and
|
|
37
|
+
will take appropriate and fair corrective action in response to any behavior that they deem
|
|
38
|
+
inappropriate, threatening, offensive, or harmful.
|
|
39
|
+
|
|
40
|
+
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code,
|
|
41
|
+
wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will
|
|
42
|
+
communicate reasons for moderation decisions when appropriate.
|
|
43
|
+
|
|
44
|
+
## Scope
|
|
45
|
+
|
|
46
|
+
This Code of Conduct applies within all community spaces, and also applies when an individual is
|
|
47
|
+
officially representing the community in public spaces.
|
|
48
|
+
|
|
49
|
+
## Enforcement
|
|
50
|
+
|
|
51
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community
|
|
52
|
+
leaders responsible for enforcement at **rn.wolfe@gmail.com**. All complaints will be reviewed and
|
|
53
|
+
investigated promptly and fairly.
|
|
54
|
+
|
|
55
|
+
All community leaders are obligated to respect the privacy and security of the reporter of any
|
|
56
|
+
incident.
|
|
57
|
+
|
|
58
|
+
## Enforcement Guidelines
|
|
59
|
+
|
|
60
|
+
Community leaders will follow these Community Impact Guidelines in determining the consequences for any
|
|
61
|
+
action they deem in violation of this Code of Conduct:
|
|
62
|
+
|
|
63
|
+
### 1. Correction
|
|
64
|
+
|
|
65
|
+
**Community Impact:** Use of inappropriate language or other behavior deemed unprofessional or unwelcome.
|
|
66
|
+
|
|
67
|
+
**Consequence:** A private, written warning from community leaders, providing clarity around the nature
|
|
68
|
+
of the violation and an explanation of why the behavior was inappropriate. A public apology may be
|
|
69
|
+
requested.
|
|
70
|
+
|
|
71
|
+
### 2. Warning
|
|
72
|
+
|
|
73
|
+
**Community Impact:** A violation through a single incident or series of actions.
|
|
74
|
+
|
|
75
|
+
**Consequence:** A warning with consequences for continued behavior. No interaction with the people
|
|
76
|
+
involved for a specified period of time. Violating these terms may lead to a temporary or permanent ban.
|
|
77
|
+
|
|
78
|
+
### 3. Temporary Ban
|
|
79
|
+
|
|
80
|
+
**Community Impact:** A serious violation of community standards, including sustained inappropriate
|
|
81
|
+
behavior.
|
|
82
|
+
|
|
83
|
+
**Consequence:** A temporary ban from any sort of interaction or public communication with the
|
|
84
|
+
community for a specified period of time. Violating these terms may lead to a permanent ban.
|
|
85
|
+
|
|
86
|
+
### 4. Permanent Ban
|
|
87
|
+
|
|
88
|
+
**Community Impact:** Demonstrating a pattern of violation of community standards, harassment of an
|
|
89
|
+
individual, or aggression toward or disparagement of classes of individuals.
|
|
90
|
+
|
|
91
|
+
**Consequence:** A permanent ban from any sort of public interaction within the community.
|
|
92
|
+
|
|
93
|
+
## Attribution
|
|
94
|
+
|
|
95
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 3.0, available at
|
|
96
|
+
<https://www.contributor-covenant.org/version/3/0/code_of_conduct/>. Contributor Covenant is stewarded
|
|
97
|
+
by the Organization for Ethical Source and licensed under CC BY-SA 4.0.
|
|
98
|
+
|
|
99
|
+
[homepage]: https://www.contributor-covenant.org
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Contributing to gfly
|
|
2
|
+
|
|
3
|
+
Thanks for helping! gfly is an agent-first, read-only Google Flights CLI. `spec.md` is the source
|
|
4
|
+
of truth for what it is; the **agent-CLI contract** (read-only, stable JSON, structured errors,
|
|
5
|
+
bounded output) is non-negotiable — keep it intact.
|
|
6
|
+
|
|
7
|
+
## Setup
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
uv sync --extra dev # Python >= 3.10, uv-managed
|
|
11
|
+
uv run pytest -q # tests must stay green
|
|
12
|
+
uv run gfly schema # machine-readable command tree
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Develop
|
|
16
|
+
|
|
17
|
+
- **Layout:** `src/gfly/cli.py` (Click grammar + runtime), `backend.py` (google/serpapi engines),
|
|
18
|
+
`throttle.py` (persistent politeness), `auth.py` (keyring), `output.py` (output discipline —
|
|
19
|
+
don't break stdout=data/stderr=chatter), `errors.py` (exit-code table). See `AGENTS.md`.
|
|
20
|
+
- **Heavy imports stay lazy** (inside the functions that use them) so `--help`/`schema` stay fast.
|
|
21
|
+
- **Read-only:** no command may mutate remote state. Don't add mutations without revisiting `spec.md`.
|
|
22
|
+
- **Output contract is append-only:** add fields freely; never rename/remove. A breaking shape change
|
|
23
|
+
means bumping `SCHEMA_VERSION` and updating `tests/test_schema_snapshot.py` in the same PR.
|
|
24
|
+
- **Secrets:** stdin/env only, never argv (contract §7).
|
|
25
|
+
|
|
26
|
+
## Tests
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
uv run pytest -q
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Network is mocked in tests (`tests/conftest.py` monkeypatches the two backend entry points). The
|
|
33
|
+
**schema-snapshot test is the CI gate** — if it fails, you changed the agent-facing contract; make
|
|
34
|
+
that a deliberate, reviewed diff.
|
|
35
|
+
|
|
36
|
+
## Pull requests
|
|
37
|
+
|
|
38
|
+
- Use **[Conventional Commits](https://www.conventionalcommits.org/)** (`feat:`, `fix:`, `docs:`,
|
|
39
|
+
`refactor:`, `test:`, `chore:`) — they drive the changelog and semver bump.
|
|
40
|
+
- Sign off your commits (**DCO**): `git commit -s`. No CLA.
|
|
41
|
+
- Keep PRs focused; update `CHANGELOG.md` (Unreleased) and docs/`SKILL.md` when behavior changes.
|
|
42
|
+
- Green CI required: tests + `gfly schema` smoke.
|
|
43
|
+
|
|
44
|
+
## Reporting bugs / security
|
|
45
|
+
|
|
46
|
+
- Bugs: open an issue (the form asks for `gfly --version`, OS, backend, repro, and the JSON error).
|
|
47
|
+
- Security: **do not** open a public issue — see [SECURITY.md](SECURITY.md).
|