pythia-plsql 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.
- pythia_plsql-0.1.0/LICENSE +21 -0
- pythia_plsql-0.1.0/PKG-INFO +167 -0
- pythia_plsql-0.1.0/README.md +153 -0
- pythia_plsql-0.1.0/pyproject.toml +32 -0
- pythia_plsql-0.1.0/queries/compile-errors.sql +17 -0
- pythia_plsql-0.1.0/queries/dependencies.sql +30 -0
- pythia_plsql-0.1.0/queries/impact.sql +26 -0
- pythia_plsql-0.1.0/queries/invalid-objects.sql +11 -0
- pythia_plsql-0.1.0/queries/name-occupants.sql +15 -0
- pythia_plsql-0.1.0/queries/object-source.sql +13 -0
- pythia_plsql-0.1.0/queries/plscope-enabled.sql +9 -0
- pythia_plsql-0.1.0/queries/plscope-statements.sql +21 -0
- pythia_plsql-0.1.0/queries/plscope-usages.sql +18 -0
- pythia_plsql-0.1.0/queries/session-privileges.sql +8 -0
- pythia_plsql-0.1.0/queries/similar-candidates.sql +13 -0
- pythia_plsql-0.1.0/queries/source.sql +10 -0
- pythia_plsql-0.1.0/scripts/pythia.py +1566 -0
- pythia_plsql-0.1.0/scripts/pythia_plsql.egg-info/PKG-INFO +167 -0
- pythia_plsql-0.1.0/scripts/pythia_plsql.egg-info/SOURCES.txt +37 -0
- pythia_plsql-0.1.0/scripts/pythia_plsql.egg-info/dependency_links.txt +1 -0
- pythia_plsql-0.1.0/scripts/pythia_plsql.egg-info/entry_points.txt +2 -0
- pythia_plsql-0.1.0/scripts/pythia_plsql.egg-info/requires.txt +1 -0
- pythia_plsql-0.1.0/scripts/pythia_plsql.egg-info/top_level.txt +3 -0
- pythia_plsql-0.1.0/setup.cfg +4 -0
- pythia_plsql-0.1.0/skills/plsql-apply/SKILL.md +124 -0
- pythia_plsql-0.1.0/skills/plsql-explore/SKILL.md +61 -0
- pythia_plsql-0.1.0/skills/plsql-explore/reference/data-dictionary.md +61 -0
- pythia_plsql-0.1.0/skills/plsql-impact/SKILL.md +56 -0
- pythia_plsql-0.1.0/skills/plsql-review/SKILL.md +50 -0
- pythia_plsql-0.1.0/skills/plsql-review/reference/antipatterns.md +106 -0
- pythia_plsql-0.1.0/skills/plsql-setup/SKILL.md +76 -0
- pythia_plsql-0.1.0/skills/plsql-skill-author/SKILL.md +94 -0
- pythia_plsql-0.1.0/skills/plsql-write/SKILL.md +52 -0
- pythia_plsql-0.1.0/skills/plsql-write/reference/patterns.md +99 -0
- pythia_plsql-0.1.0/tests/test_install.py +109 -0
- pythia_plsql-0.1.0/tests/test_phase1.py +271 -0
- pythia_plsql-0.1.0/tests/test_phase2.py +135 -0
- pythia_plsql-0.1.0/tests/test_phase3.py +510 -0
- pythia_plsql-0.1.0/tests/test_phase5.py +114 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 thaild
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pythia-plsql
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: PL/SQL development for AI agents on Oracle Database - expert data-dictionary queries, impact analysis, and a snapshot-verified write path with honest rollback.
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/thaildhe172591/pythia
|
|
7
|
+
Project-URL: Repository, https://github.com/thaildhe172591/pythia
|
|
8
|
+
Keywords: oracle,plsql,database,agent-skills,sql
|
|
9
|
+
Requires-Python: >=3.9
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Requires-Dist: oracledb>=2.0
|
|
13
|
+
Dynamic: license-file
|
|
14
|
+
|
|
15
|
+
# pythia
|
|
16
|
+
|
|
17
|
+
> Oracle's MCP gives your agent a connection. **pythia gives it the judgment to use it.**
|
|
18
|
+
|
|
19
|
+
[](https://github.com/thaildhe172591/pythia/actions/workflows/ci.yml)
|
|
20
|
+
[](LICENSE)
|
|
21
|
+

|
|
22
|
+
|
|
23
|
+
An Agent Skills + CLI kit for developing PL/SQL on Oracle Database with AI coding
|
|
24
|
+
agents (Claude Code, Codex, Cursor — any of the 76 agents `npx skills` supports).
|
|
25
|
+
Explore schemas too big to dump, measure blast radius **before** touching anything,
|
|
26
|
+
and land changes through a snapshot-verified write path that never lies about rollback.
|
|
27
|
+
|
|
28
|
+
## Why ask the database instead of reading dumps
|
|
29
|
+
|
|
30
|
+
A real mid-size system, repo export vs live database, audited in 2026:
|
|
31
|
+
|
|
32
|
+
| Object type | In the dump | In the database | Verdict |
|
|
33
|
+
|---|---|---|---|
|
|
34
|
+
| Procedures | 3,827 | 3,827 | matched |
|
|
35
|
+
| Tables | 952 | 952 | matched |
|
|
36
|
+
| **Types** | **0** | **115** | **all missing** |
|
|
37
|
+
| **Packages** | **0** | **9** | **all missing** |
|
|
38
|
+
| **Indexes** | **116** | **1,016** | **~89% missing** |
|
|
39
|
+
|
|
40
|
+
Code that "reads fine" against the dump references types and packages the dump never
|
|
41
|
+
heard of. Every pythia command asks the live data dictionary instead — and every
|
|
42
|
+
truncated output says so, so an agent never mistakes a partial answer for a full one.
|
|
43
|
+
|
|
44
|
+
## How it works
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
developer chats with the agent
|
|
48
|
+
│
|
|
49
|
+
skills/ teach the agent when to ask, when to stop, when to ask YOU
|
|
50
|
+
│
|
|
51
|
+
pythia CLI — expert queries, impact analysis, the six-step write path
|
|
52
|
+
│
|
|
53
|
+
Oracle data dictionary: ALL_SOURCE, ALL_DEPENDENCIES, ALL_ERRORS, PL/Scope
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The write path is the heart: **snapshot → impact → preview → apply → verify → report**.
|
|
57
|
+
DDL self-commits in Oracle — the snapshot is the only real undo, so it always runs
|
|
58
|
+
first and no flag can turn it off. A 6-hex token binds the write to exactly what was
|
|
59
|
+
previewed; exit codes make honesty machine-readable
|
|
60
|
+
(`0` clean · `1` refused · `3` **written but broken — never reported as success**).
|
|
61
|
+
|
|
62
|
+
## Install
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npx pythia-plsql # everything: pip install + skills picker + config scaffold
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Or the same thing piecewise:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install pythia-plsql # the CLI (thin driver — no Oracle Instant Client needed)
|
|
72
|
+
pythia install # skills into your agent + .pythia/connections.json scaffold
|
|
73
|
+
pythia check # fill in connections.json first, then verify
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The pip package is the whole kit: with Node.js present, `pythia install`
|
|
77
|
+
runs `npx skills add` (77 agents, symlinked updates; `--source <git-url>`
|
|
78
|
+
for internal mirrors) — without Node it copies the bundled skill pack into
|
|
79
|
+
`.claude/skills/` and `.agents/skills/`. Skills alone: `npx skills add
|
|
80
|
+
thaildhe172591/pythia`, or `/plugin marketplace add thaildhe172591/pythia`.
|
|
81
|
+
|
|
82
|
+
Running from a clone works too — `python scripts/pythia.py <command>`; every
|
|
83
|
+
printed follow-up command matches how you invoked it. Windows, macOS, Linux
|
|
84
|
+
and WSL are all CI-tested.
|
|
85
|
+
|
|
86
|
+
## Commands
|
|
87
|
+
|
|
88
|
+
| Read | Understand | Write |
|
|
89
|
+
|---|---|---|
|
|
90
|
+
| `check` connectivity + counts | `deps` what it depends on | `apply` the six-step write |
|
|
91
|
+
| `ls` find objects | `impact` what depends on it | `journal` list · diff · export · restore |
|
|
92
|
+
| `src` source, compiler line numbers | `errors` compile errors, line:col | `policy` show · set |
|
|
93
|
+
| `args` signatures | `invalid` everything broken | |
|
|
94
|
+
| `ddl` via DBMS_METADATA | `plscope` exact identifier usages | |
|
|
95
|
+
| `cols` columns + types | `similar` programs named like this | |
|
|
96
|
+
| `grep` search all source | | |
|
|
97
|
+
| `sql` free query (SELECT/WITH only) | | |
|
|
98
|
+
|
|
99
|
+
Every command takes `--json` (machine output), `--conn` (pick a connection), and
|
|
100
|
+
caps output with explicit truncation markers so context windows stay intact.
|
|
101
|
+
|
|
102
|
+
**Your house style is config, not folklore**: put naming patterns in
|
|
103
|
+
`.pythia/conventions.json` and apply previews warn when a new object's name
|
|
104
|
+
drifts; put the prose rules in `.pythia/conventions.md` and the skills make
|
|
105
|
+
every agent read them first (`pythia conventions` shows both).
|
|
106
|
+
|
|
107
|
+
## Security & write policy
|
|
108
|
+
|
|
109
|
+
**The account is the real security layer** — the policy file is an application-side
|
|
110
|
+
fence. Give the agent its own revocable credential with proxy authentication
|
|
111
|
+
(`agent_user[schema_owner]`, no `ANY` privileges, no owner password shared):
|
|
112
|
+
see [`examples/agent-user-setup.example.sql`](examples/agent-user-setup.example.sql).
|
|
113
|
+
`pythia check` warns when the session runs with more power than the task needs.
|
|
114
|
+
|
|
115
|
+
Per-group write policy, `.pythia/policy.json` (defaults shown):
|
|
116
|
+
|
|
117
|
+
| Group | Default | Is rollback real? |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| `plsql_source` | `confirm` | **Yes — completely.** Source is recoverable from `ALL_SOURCE`. |
|
|
120
|
+
| `data_dml` | `deny` | **No.** After commit only Flashback Query remains, within undo retention. |
|
|
121
|
+
| `structural` | `deny` | **Almost never.** `DROP COLUMN` is permanent; a dropped table may be in the Recycle Bin. |
|
|
122
|
+
| `grants` | `deny` | Yes, but by hand. |
|
|
123
|
+
| `session` | `allow` | Not needed. |
|
|
124
|
+
|
|
125
|
+
The groups that cannot be snapshotted default to `deny` — and the refusal says that,
|
|
126
|
+
instead of "policy forbids it". Anonymous PL/SQL blocks are refused outright.
|
|
127
|
+
Unrecognized statements are refused, never guessed into a group.
|
|
128
|
+
|
|
129
|
+
Reads may flow through Oracle's official SQLcl MCP server (`sql -mcp`, keep `-R 4`);
|
|
130
|
+
it audits every interaction in `DBTOOLS$MCP_LOG`. **Writes never do** — only
|
|
131
|
+
`pythia apply` has the snapshot, preview, verify and journal.
|
|
132
|
+
|
|
133
|
+
## Skills
|
|
134
|
+
|
|
135
|
+
Seven skills teach the agent the workflow — superpowers-style gates, not suggestions:
|
|
136
|
+
|
|
137
|
+
`plsql-setup` · `plsql-explore` · `plsql-impact` (impact **before** any change) ·
|
|
138
|
+
`plsql-write` (copy the codebase's conventions) · `plsql-apply` (the gate: the
|
|
139
|
+
developer sees the preview and approves in chat before anything is written) ·
|
|
140
|
+
`plsql-review` (seven antipatterns) · `plsql-skill-author` (capture *your team's*
|
|
141
|
+
workflow as a new skill, mined from the live schema).
|
|
142
|
+
|
|
143
|
+
## Compatibility
|
|
144
|
+
|
|
145
|
+
| | |
|
|
146
|
+
|---|---|
|
|
147
|
+
| OS | Windows, macOS, Linux, WSL — full test matrix in CI |
|
|
148
|
+
| Python | 3.9+ · stdlib + `python-oracledb` (thin mode) only |
|
|
149
|
+
| Oracle | core works broadly; PL/Scope statement capture needs 12.2+; license-safe views only |
|
|
150
|
+
| Agents | any `npx skills` agent (76) · native Claude Code plugin |
|
|
151
|
+
|
|
152
|
+
## Star History
|
|
153
|
+
|
|
154
|
+
<a href="https://www.star-history.com/?repos=thaildhe172591%2Fpythia&type=date&legend=top-left">
|
|
155
|
+
<picture>
|
|
156
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=thaildhe172591/pythia&type=date&theme=dark&legend=top-left&sealed_token=OnPCuXPZZEbpQk5_Eor5ZB0fTeMzMN1nmrsDJ8qqahouiJt4-IoDvjONdD05i2D2PhfDC5kwd6CUQeBsWGNV20gt2-4HSD-RygX3h0Ni0lrbQnRh60EN3A" />
|
|
157
|
+
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=thaildhe172591/pythia&type=date&legend=top-left&sealed_token=OnPCuXPZZEbpQk5_Eor5ZB0fTeMzMN1nmrsDJ8qqahouiJt4-IoDvjONdD05i2D2PhfDC5kwd6CUQeBsWGNV20gt2-4HSD-RygX3h0Ni0lrbQnRh60EN3A" />
|
|
158
|
+
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=thaildhe172591/pythia&type=date&legend=top-left&sealed_token=OnPCuXPZZEbpQk5_Eor5ZB0fTeMzMN1nmrsDJ8qqahouiJt4-IoDvjONdD05i2D2PhfDC5kwd6CUQeBsWGNV20gt2-4HSD-RygX3h0Ni0lrbQnRh60EN3A" />
|
|
159
|
+
</picture>
|
|
160
|
+
</a>
|
|
161
|
+
|
|
162
|
+
## Contributing
|
|
163
|
+
|
|
164
|
+
Tests need **no database** — the fakes prove the safety properties (snapshot before
|
|
165
|
+
write, deny touches nothing, stale tokens refused). See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
166
|
+
|
|
167
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# pythia
|
|
2
|
+
|
|
3
|
+
> Oracle's MCP gives your agent a connection. **pythia gives it the judgment to use it.**
|
|
4
|
+
|
|
5
|
+
[](https://github.com/thaildhe172591/pythia/actions/workflows/ci.yml)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
An Agent Skills + CLI kit for developing PL/SQL on Oracle Database with AI coding
|
|
10
|
+
agents (Claude Code, Codex, Cursor — any of the 76 agents `npx skills` supports).
|
|
11
|
+
Explore schemas too big to dump, measure blast radius **before** touching anything,
|
|
12
|
+
and land changes through a snapshot-verified write path that never lies about rollback.
|
|
13
|
+
|
|
14
|
+
## Why ask the database instead of reading dumps
|
|
15
|
+
|
|
16
|
+
A real mid-size system, repo export vs live database, audited in 2026:
|
|
17
|
+
|
|
18
|
+
| Object type | In the dump | In the database | Verdict |
|
|
19
|
+
|---|---|---|---|
|
|
20
|
+
| Procedures | 3,827 | 3,827 | matched |
|
|
21
|
+
| Tables | 952 | 952 | matched |
|
|
22
|
+
| **Types** | **0** | **115** | **all missing** |
|
|
23
|
+
| **Packages** | **0** | **9** | **all missing** |
|
|
24
|
+
| **Indexes** | **116** | **1,016** | **~89% missing** |
|
|
25
|
+
|
|
26
|
+
Code that "reads fine" against the dump references types and packages the dump never
|
|
27
|
+
heard of. Every pythia command asks the live data dictionary instead — and every
|
|
28
|
+
truncated output says so, so an agent never mistakes a partial answer for a full one.
|
|
29
|
+
|
|
30
|
+
## How it works
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
developer chats with the agent
|
|
34
|
+
│
|
|
35
|
+
skills/ teach the agent when to ask, when to stop, when to ask YOU
|
|
36
|
+
│
|
|
37
|
+
pythia CLI — expert queries, impact analysis, the six-step write path
|
|
38
|
+
│
|
|
39
|
+
Oracle data dictionary: ALL_SOURCE, ALL_DEPENDENCIES, ALL_ERRORS, PL/Scope
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The write path is the heart: **snapshot → impact → preview → apply → verify → report**.
|
|
43
|
+
DDL self-commits in Oracle — the snapshot is the only real undo, so it always runs
|
|
44
|
+
first and no flag can turn it off. A 6-hex token binds the write to exactly what was
|
|
45
|
+
previewed; exit codes make honesty machine-readable
|
|
46
|
+
(`0` clean · `1` refused · `3` **written but broken — never reported as success**).
|
|
47
|
+
|
|
48
|
+
## Install
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npx pythia-plsql # everything: pip install + skills picker + config scaffold
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Or the same thing piecewise:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install pythia-plsql # the CLI (thin driver — no Oracle Instant Client needed)
|
|
58
|
+
pythia install # skills into your agent + .pythia/connections.json scaffold
|
|
59
|
+
pythia check # fill in connections.json first, then verify
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The pip package is the whole kit: with Node.js present, `pythia install`
|
|
63
|
+
runs `npx skills add` (77 agents, symlinked updates; `--source <git-url>`
|
|
64
|
+
for internal mirrors) — without Node it copies the bundled skill pack into
|
|
65
|
+
`.claude/skills/` and `.agents/skills/`. Skills alone: `npx skills add
|
|
66
|
+
thaildhe172591/pythia`, or `/plugin marketplace add thaildhe172591/pythia`.
|
|
67
|
+
|
|
68
|
+
Running from a clone works too — `python scripts/pythia.py <command>`; every
|
|
69
|
+
printed follow-up command matches how you invoked it. Windows, macOS, Linux
|
|
70
|
+
and WSL are all CI-tested.
|
|
71
|
+
|
|
72
|
+
## Commands
|
|
73
|
+
|
|
74
|
+
| Read | Understand | Write |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| `check` connectivity + counts | `deps` what it depends on | `apply` the six-step write |
|
|
77
|
+
| `ls` find objects | `impact` what depends on it | `journal` list · diff · export · restore |
|
|
78
|
+
| `src` source, compiler line numbers | `errors` compile errors, line:col | `policy` show · set |
|
|
79
|
+
| `args` signatures | `invalid` everything broken | |
|
|
80
|
+
| `ddl` via DBMS_METADATA | `plscope` exact identifier usages | |
|
|
81
|
+
| `cols` columns + types | `similar` programs named like this | |
|
|
82
|
+
| `grep` search all source | | |
|
|
83
|
+
| `sql` free query (SELECT/WITH only) | | |
|
|
84
|
+
|
|
85
|
+
Every command takes `--json` (machine output), `--conn` (pick a connection), and
|
|
86
|
+
caps output with explicit truncation markers so context windows stay intact.
|
|
87
|
+
|
|
88
|
+
**Your house style is config, not folklore**: put naming patterns in
|
|
89
|
+
`.pythia/conventions.json` and apply previews warn when a new object's name
|
|
90
|
+
drifts; put the prose rules in `.pythia/conventions.md` and the skills make
|
|
91
|
+
every agent read them first (`pythia conventions` shows both).
|
|
92
|
+
|
|
93
|
+
## Security & write policy
|
|
94
|
+
|
|
95
|
+
**The account is the real security layer** — the policy file is an application-side
|
|
96
|
+
fence. Give the agent its own revocable credential with proxy authentication
|
|
97
|
+
(`agent_user[schema_owner]`, no `ANY` privileges, no owner password shared):
|
|
98
|
+
see [`examples/agent-user-setup.example.sql`](examples/agent-user-setup.example.sql).
|
|
99
|
+
`pythia check` warns when the session runs with more power than the task needs.
|
|
100
|
+
|
|
101
|
+
Per-group write policy, `.pythia/policy.json` (defaults shown):
|
|
102
|
+
|
|
103
|
+
| Group | Default | Is rollback real? |
|
|
104
|
+
|---|---|---|
|
|
105
|
+
| `plsql_source` | `confirm` | **Yes — completely.** Source is recoverable from `ALL_SOURCE`. |
|
|
106
|
+
| `data_dml` | `deny` | **No.** After commit only Flashback Query remains, within undo retention. |
|
|
107
|
+
| `structural` | `deny` | **Almost never.** `DROP COLUMN` is permanent; a dropped table may be in the Recycle Bin. |
|
|
108
|
+
| `grants` | `deny` | Yes, but by hand. |
|
|
109
|
+
| `session` | `allow` | Not needed. |
|
|
110
|
+
|
|
111
|
+
The groups that cannot be snapshotted default to `deny` — and the refusal says that,
|
|
112
|
+
instead of "policy forbids it". Anonymous PL/SQL blocks are refused outright.
|
|
113
|
+
Unrecognized statements are refused, never guessed into a group.
|
|
114
|
+
|
|
115
|
+
Reads may flow through Oracle's official SQLcl MCP server (`sql -mcp`, keep `-R 4`);
|
|
116
|
+
it audits every interaction in `DBTOOLS$MCP_LOG`. **Writes never do** — only
|
|
117
|
+
`pythia apply` has the snapshot, preview, verify and journal.
|
|
118
|
+
|
|
119
|
+
## Skills
|
|
120
|
+
|
|
121
|
+
Seven skills teach the agent the workflow — superpowers-style gates, not suggestions:
|
|
122
|
+
|
|
123
|
+
`plsql-setup` · `plsql-explore` · `plsql-impact` (impact **before** any change) ·
|
|
124
|
+
`plsql-write` (copy the codebase's conventions) · `plsql-apply` (the gate: the
|
|
125
|
+
developer sees the preview and approves in chat before anything is written) ·
|
|
126
|
+
`plsql-review` (seven antipatterns) · `plsql-skill-author` (capture *your team's*
|
|
127
|
+
workflow as a new skill, mined from the live schema).
|
|
128
|
+
|
|
129
|
+
## Compatibility
|
|
130
|
+
|
|
131
|
+
| | |
|
|
132
|
+
|---|---|
|
|
133
|
+
| OS | Windows, macOS, Linux, WSL — full test matrix in CI |
|
|
134
|
+
| Python | 3.9+ · stdlib + `python-oracledb` (thin mode) only |
|
|
135
|
+
| Oracle | core works broadly; PL/Scope statement capture needs 12.2+; license-safe views only |
|
|
136
|
+
| Agents | any `npx skills` agent (76) · native Claude Code plugin |
|
|
137
|
+
|
|
138
|
+
## Star History
|
|
139
|
+
|
|
140
|
+
<a href="https://www.star-history.com/?repos=thaildhe172591%2Fpythia&type=date&legend=top-left">
|
|
141
|
+
<picture>
|
|
142
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=thaildhe172591/pythia&type=date&theme=dark&legend=top-left&sealed_token=OnPCuXPZZEbpQk5_Eor5ZB0fTeMzMN1nmrsDJ8qqahouiJt4-IoDvjONdD05i2D2PhfDC5kwd6CUQeBsWGNV20gt2-4HSD-RygX3h0Ni0lrbQnRh60EN3A" />
|
|
143
|
+
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=thaildhe172591/pythia&type=date&legend=top-left&sealed_token=OnPCuXPZZEbpQk5_Eor5ZB0fTeMzMN1nmrsDJ8qqahouiJt4-IoDvjONdD05i2D2PhfDC5kwd6CUQeBsWGNV20gt2-4HSD-RygX3h0Ni0lrbQnRh60EN3A" />
|
|
144
|
+
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=thaildhe172591/pythia&type=date&legend=top-left&sealed_token=OnPCuXPZZEbpQk5_Eor5ZB0fTeMzMN1nmrsDJ8qqahouiJt4-IoDvjONdD05i2D2PhfDC5kwd6CUQeBsWGNV20gt2-4HSD-RygX3h0Ni0lrbQnRh60EN3A" />
|
|
145
|
+
</picture>
|
|
146
|
+
</a>
|
|
147
|
+
|
|
148
|
+
## Contributing
|
|
149
|
+
|
|
150
|
+
Tests need **no database** — the fakes prove the safety properties (snapshot before
|
|
151
|
+
write, deny touches nothing, stale tokens refused). See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
152
|
+
|
|
153
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=64"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pythia-plsql"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "PL/SQL development for AI agents on Oracle Database - expert data-dictionary queries, impact analysis, and a snapshot-verified write path with honest rollback."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
dependencies = ["oracledb>=2.0"]
|
|
13
|
+
keywords = ["oracle", "plsql", "database", "agent-skills", "sql"]
|
|
14
|
+
|
|
15
|
+
[project.urls]
|
|
16
|
+
Homepage = "https://github.com/thaildhe172591/pythia"
|
|
17
|
+
Repository = "https://github.com/thaildhe172591/pythia"
|
|
18
|
+
|
|
19
|
+
[project.scripts]
|
|
20
|
+
pythia = "pythia:main"
|
|
21
|
+
|
|
22
|
+
# scripts/pythia.py stays the single source; the wheel also carries queries/
|
|
23
|
+
# and skills/ as package data, so the pip install alone is the whole kit —
|
|
24
|
+
# load_query() and the no-Node skills fallback both work outside the repo.
|
|
25
|
+
[tool.setuptools]
|
|
26
|
+
package-dir = { "" = "scripts", "pythia_queries" = "queries", "pythia_skills" = "skills" }
|
|
27
|
+
py-modules = ["pythia"]
|
|
28
|
+
packages = ["pythia_queries", "pythia_skills"]
|
|
29
|
+
|
|
30
|
+
[tool.setuptools.package-data]
|
|
31
|
+
pythia_queries = ["*.sql"]
|
|
32
|
+
pythia_skills = ["*/SKILL.md", "*/reference/*.md"]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
-- Purpose: compilation errors and warnings with the exact line and column
|
|
2
|
+
-- Oracle reports, so a fix can be aimed rather than guessed. This
|
|
3
|
+
-- closes the compile-read-fix loop.
|
|
4
|
+
-- Binds: :s schema (object owner)
|
|
5
|
+
-- :n object name, or NULL for every object in the schema
|
|
6
|
+
-- Returns: NAME, TYPE, SEQUENCE, LINE, POSITION, ATTRIBUTE, TEXT
|
|
7
|
+
select name,
|
|
8
|
+
type,
|
|
9
|
+
sequence,
|
|
10
|
+
line,
|
|
11
|
+
position,
|
|
12
|
+
attribute,
|
|
13
|
+
text
|
|
14
|
+
from all_errors
|
|
15
|
+
where owner = :s
|
|
16
|
+
and (:n is null or name = upper(:n))
|
|
17
|
+
order by name, sequence
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
-- Purpose: what an object depends on, walked downward. NOCYCLE survives
|
|
2
|
+
-- circular references; the depth bound sits in CONNECT BY so the
|
|
3
|
+
-- walk is pruned rather than filtered after the fact.
|
|
4
|
+
-- Oracle's own built-ins (SYS.STANDARD and friends) are excluded
|
|
5
|
+
-- unless asked for: every PL/SQL object depends on them, so they
|
|
6
|
+
-- crowd out the dependencies a developer is actually looking for.
|
|
7
|
+
-- The test is applied in both START WITH and CONNECT BY, so an
|
|
8
|
+
-- excluded object takes its whole subtree with it instead of
|
|
9
|
+
-- leaving its children behind as orphans.
|
|
10
|
+
-- Binds: :s schema (owner of the starting object)
|
|
11
|
+
-- :n starting object name
|
|
12
|
+
-- :depth levels to walk (1 = direct dependencies only)
|
|
13
|
+
-- :with_sys 1 to include SYS/PUBLIC built-ins, 0 to leave them out
|
|
14
|
+
-- Returns: LVL, OWNER, NAME, TYPE, DEPENDENCY_TYPE
|
|
15
|
+
select level lvl,
|
|
16
|
+
d.referenced_owner owner,
|
|
17
|
+
d.referenced_name name,
|
|
18
|
+
d.referenced_type type,
|
|
19
|
+
d.dependency_type
|
|
20
|
+
from all_dependencies d
|
|
21
|
+
start with d.owner = :s
|
|
22
|
+
and d.name = upper(:n)
|
|
23
|
+
and (:with_sys = 1 or d.referenced_owner not in ('SYS', 'PUBLIC'))
|
|
24
|
+
connect by nocycle
|
|
25
|
+
prior d.referenced_owner = d.owner
|
|
26
|
+
and prior d.referenced_name = d.name
|
|
27
|
+
and prior d.referenced_type = d.type
|
|
28
|
+
and level <= :depth
|
|
29
|
+
and (:with_sys = 1 or d.referenced_owner not in ('SYS', 'PUBLIC'))
|
|
30
|
+
order siblings by d.referenced_type, d.referenced_name
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
-- Purpose: what depends on an object — everything a change to it can break.
|
|
2
|
+
-- The reverse of dependencies.sql. Status comes from a scalar
|
|
3
|
+
-- subquery so the hierarchical row order survives.
|
|
4
|
+
-- Binds: :s schema (owner of the starting object)
|
|
5
|
+
-- :n starting object name
|
|
6
|
+
-- :depth levels to walk (1 = direct dependents only)
|
|
7
|
+
-- Returns: LVL, OWNER, NAME, TYPE, STATUS, DEPENDENCY_TYPE
|
|
8
|
+
select level lvl,
|
|
9
|
+
d.owner,
|
|
10
|
+
d.name,
|
|
11
|
+
d.type,
|
|
12
|
+
(select o.status
|
|
13
|
+
from all_objects o
|
|
14
|
+
where o.owner = d.owner
|
|
15
|
+
and o.object_name = d.name
|
|
16
|
+
and o.object_type = d.type) status,
|
|
17
|
+
d.dependency_type
|
|
18
|
+
from all_dependencies d
|
|
19
|
+
start with d.referenced_owner = :s
|
|
20
|
+
and d.referenced_name = upper(:n)
|
|
21
|
+
connect by nocycle
|
|
22
|
+
prior d.owner = d.referenced_owner
|
|
23
|
+
and prior d.name = d.referenced_name
|
|
24
|
+
and prior d.type = d.referenced_type
|
|
25
|
+
and level <= :depth
|
|
26
|
+
order siblings by d.type, d.name
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
-- Purpose: every INVALID object in the schema. Captured before and after a
|
|
2
|
+
-- change, this is what proves a fix did not break something else.
|
|
3
|
+
-- Binds: :s schema (object owner)
|
|
4
|
+
-- Returns: OBJECT_NAME, OBJECT_TYPE, LAST_DDL
|
|
5
|
+
select object_name,
|
|
6
|
+
object_type,
|
|
7
|
+
to_char(last_ddl_time, 'yyyy-mm-dd hh24:mi:ss') last_ddl
|
|
8
|
+
from all_objects
|
|
9
|
+
where owner = :s
|
|
10
|
+
and status = 'INVALID'
|
|
11
|
+
order by object_type, object_name
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
-- Purpose: which object types currently hold a name in the schema's main
|
|
2
|
+
-- namespace. CREATE OR REPLACE cannot change an object's type, so a
|
|
3
|
+
-- name held by a different type must be refused at preview time —
|
|
4
|
+
-- otherwise the preview promises what the database will reject with
|
|
5
|
+
-- ORA-00955. Found by an agent during the first field test.
|
|
6
|
+
-- Binds: :s schema (object owner)
|
|
7
|
+
-- :n object name
|
|
8
|
+
-- Returns: OBJECT_TYPE
|
|
9
|
+
select object_type
|
|
10
|
+
from all_objects
|
|
11
|
+
where owner = :s
|
|
12
|
+
and object_name = upper(:n)
|
|
13
|
+
and object_type in ('PROCEDURE', 'FUNCTION', 'PACKAGE', 'PACKAGE BODY',
|
|
14
|
+
'TYPE', 'TYPE BODY', 'VIEW', 'TABLE',
|
|
15
|
+
'MATERIALIZED VIEW', 'SEQUENCE', 'SYNONYM')
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
-- Purpose: source of one specific unit — the snapshot read that runs before
|
|
2
|
+
-- every write. PACKAGE and PACKAGE BODY are distinct objects, so the
|
|
3
|
+
-- type is part of the identity, not a filter convenience.
|
|
4
|
+
-- Binds: :s schema (object owner)
|
|
5
|
+
-- :n object name
|
|
6
|
+
-- :t object type exactly as in ALL_SOURCE (e.g. PACKAGE BODY)
|
|
7
|
+
-- Returns: TEXT
|
|
8
|
+
select text
|
|
9
|
+
from all_source
|
|
10
|
+
where owner = :s
|
|
11
|
+
and name = upper(:n)
|
|
12
|
+
and type = upper(:t)
|
|
13
|
+
order by line
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
-- Purpose: one-row probe telling an empty result apart from a schema that was
|
|
2
|
+
-- never compiled with PL/Scope — the difference between "not found"
|
|
3
|
+
-- and "cannot know".
|
|
4
|
+
-- Binds: :s schema (object owner)
|
|
5
|
+
-- Returns: ENABLED
|
|
6
|
+
select 1 enabled
|
|
7
|
+
from all_identifiers
|
|
8
|
+
where owner = :s
|
|
9
|
+
and rownum = 1
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
-- Purpose: the SQL statements that touch a table, and where they sit. Answers
|
|
2
|
+
-- "which program writes to this table?" exactly. Needs PL/Scope with
|
|
3
|
+
-- STATEMENTS:ALL (Oracle 12.2+).
|
|
4
|
+
-- Binds: :s schema (object owner)
|
|
5
|
+
-- :n table name
|
|
6
|
+
-- Returns: SQL_TYPE, OBJECT_NAME, OBJECT_TYPE, LINE, COL
|
|
7
|
+
select s.type sql_type,
|
|
8
|
+
s.object_name,
|
|
9
|
+
s.object_type,
|
|
10
|
+
s.line,
|
|
11
|
+
s.col
|
|
12
|
+
from all_statements s
|
|
13
|
+
join all_identifiers i
|
|
14
|
+
on i.owner = s.owner
|
|
15
|
+
and i.object_name = s.object_name
|
|
16
|
+
and i.object_type = s.object_type
|
|
17
|
+
and i.usage_context_id = s.usage_id
|
|
18
|
+
where s.owner = :s
|
|
19
|
+
and i.name = upper(:n)
|
|
20
|
+
and i.type = 'TABLE'
|
|
21
|
+
order by s.object_name, s.line
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-- Purpose: every place an identifier is declared, referenced, assigned or
|
|
2
|
+
-- called. PL/Scope records this at compile time, so it is exact where
|
|
3
|
+
-- grep can only guess. Declarations sort first.
|
|
4
|
+
-- Binds: :s schema (object owner)
|
|
5
|
+
-- :n identifier name
|
|
6
|
+
-- Returns: USAGE, OBJECT_NAME, OBJECT_TYPE, TYPE, LINE, COL, USAGE_ID
|
|
7
|
+
select usage,
|
|
8
|
+
object_name,
|
|
9
|
+
object_type,
|
|
10
|
+
type,
|
|
11
|
+
line,
|
|
12
|
+
col,
|
|
13
|
+
usage_id
|
|
14
|
+
from all_identifiers
|
|
15
|
+
where owner = :s
|
|
16
|
+
and name = upper(:n)
|
|
17
|
+
order by case usage when 'DECLARATION' then 0 else 1 end,
|
|
18
|
+
object_name, line, col
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
-- Purpose: the dangerous ANY privileges this session holds. Feeds the
|
|
2
|
+
-- one-line warning in apply previews and check — warn, never block.
|
|
3
|
+
-- Binds: (none)
|
|
4
|
+
-- Returns: PRIVILEGE
|
|
5
|
+
select privilege
|
|
6
|
+
from session_privs
|
|
7
|
+
where privilege like '%ANY%'
|
|
8
|
+
order by privilege
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
-- Purpose: the pool of programs a new one could be modelled on. Ranking runs
|
|
2
|
+
-- in Python (rank_similar) where it is unit-testable; splitting names
|
|
3
|
+
-- in SQL would need a recursive CTE and make this file unreviewable.
|
|
4
|
+
-- Binds: :s schema (object owner)
|
|
5
|
+
-- Returns: OBJECT_NAME, OBJECT_TYPE, STATUS, LAST_DDL
|
|
6
|
+
select object_name,
|
|
7
|
+
object_type,
|
|
8
|
+
status,
|
|
9
|
+
to_char(last_ddl_time, 'yyyy-mm-dd') last_ddl
|
|
10
|
+
from all_objects
|
|
11
|
+
where owner = :s
|
|
12
|
+
and object_type in ('PROCEDURE', 'FUNCTION', 'PACKAGE')
|
|
13
|
+
order by object_name
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
-- Purpose: full source of a named object, every unit (spec and body), in
|
|
2
|
+
-- compilation order. Backs the src command.
|
|
3
|
+
-- Binds: :s schema (object owner)
|
|
4
|
+
-- :n object name
|
|
5
|
+
-- Returns: TYPE, LINE, TEXT
|
|
6
|
+
select type, line, text
|
|
7
|
+
from all_source
|
|
8
|
+
where owner = :s
|
|
9
|
+
and name = upper(:n)
|
|
10
|
+
order by type, line
|