pythia-plsql 0.1.0__py3-none-any.whl
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.py +1566 -0
- pythia_plsql-0.1.0.dist-info/METADATA +167 -0
- pythia_plsql-0.1.0.dist-info/RECORD +29 -0
- pythia_plsql-0.1.0.dist-info/WHEEL +5 -0
- pythia_plsql-0.1.0.dist-info/entry_points.txt +2 -0
- pythia_plsql-0.1.0.dist-info/licenses/LICENSE +21 -0
- pythia_plsql-0.1.0.dist-info/top_level.txt +3 -0
- pythia_queries/compile-errors.sql +17 -0
- pythia_queries/dependencies.sql +30 -0
- pythia_queries/impact.sql +26 -0
- pythia_queries/invalid-objects.sql +11 -0
- pythia_queries/name-occupants.sql +15 -0
- pythia_queries/object-source.sql +13 -0
- pythia_queries/plscope-enabled.sql +9 -0
- pythia_queries/plscope-statements.sql +21 -0
- pythia_queries/plscope-usages.sql +18 -0
- pythia_queries/session-privileges.sql +8 -0
- pythia_queries/similar-candidates.sql +13 -0
- pythia_queries/source.sql +10 -0
- pythia_skills/plsql-apply/SKILL.md +124 -0
- pythia_skills/plsql-explore/SKILL.md +61 -0
- pythia_skills/plsql-explore/reference/data-dictionary.md +61 -0
- pythia_skills/plsql-impact/SKILL.md +56 -0
- pythia_skills/plsql-review/SKILL.md +50 -0
- pythia_skills/plsql-review/reference/antipatterns.md +106 -0
- pythia_skills/plsql-setup/SKILL.md +76 -0
- pythia_skills/plsql-skill-author/SKILL.md +94 -0
- pythia_skills/plsql-write/SKILL.md +52 -0
- pythia_skills/plsql-write/reference/patterns.md +99 -0
|
@@ -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,29 @@
|
|
|
1
|
+
pythia.py,sha256=odx1LIG-ve0fv5byYkVTNZT7TNQjvqxErdwutjkOoVM,66824
|
|
2
|
+
pythia_plsql-0.1.0.dist-info/licenses/LICENSE,sha256=fY6GEoq3pNfFbCVGoUQulGzhdL5NrJCnoLdc7dOA4dQ,1063
|
|
3
|
+
pythia_queries/compile-errors.sql,sha256=wUZHicAxONcAsltUSgiihYajHzuyjksUOuxeT0oRJ5Q,573
|
|
4
|
+
pythia_queries/dependencies.sql,sha256=tt1c25dOY_340eVvfzKoNB7FJFZd6Y8bCeLYmAkkxNw,1544
|
|
5
|
+
pythia_queries/impact.sql,sha256=s2AH8QW6vaj0V5PHVbvnqmiK-_wVuKI57ZtJGfWciqY,1022
|
|
6
|
+
pythia_queries/invalid-objects.sql,sha256=wa3Cw4nsxnkGa9Ik15QgTHWC1BiYdmSbOCo9mKbV0kk,439
|
|
7
|
+
pythia_queries/name-occupants.sql,sha256=lTx26iWSdG7sobCfxJNWf0tev9JbY86DPvXasFMVuxc,758
|
|
8
|
+
pythia_queries/object-source.sql,sha256=foqe7AOd_wVyLqDZ6nSe7GLK-3ct44FKewlCBS0DlEs,493
|
|
9
|
+
pythia_queries/plscope-enabled.sql,sha256=LOlpd7FFsWJ2mXSAfRBMlR2P2mwaXJZZ7OmYIiAe-Bo,324
|
|
10
|
+
pythia_queries/plscope-statements.sql,sha256=6LATpNm-3WrSHEMIWkJpI3OlUreglUnGC9mg2x0vzVw,732
|
|
11
|
+
pythia_queries/plscope-usages.sql,sha256=THcR4GbPvVA-aTWs9oAzul5L17iekUwkMWt80y_gv2Q,619
|
|
12
|
+
pythia_queries/session-privileges.sql,sha256=q5OUhFHPGaOXsdCSChBw9SUbiyVdf0fWf9dMgG551lM,280
|
|
13
|
+
pythia_queries/similar-candidates.sql,sha256=Q04BnVlJJuV1EIVaot6jkoV0zvzZhYi_1wP-tAvWwps,556
|
|
14
|
+
pythia_queries/source.sql,sha256=Q-nJ58LHAverO07hy9wOHzPsWwfdQ2h19ZyEbn0fUaQ,328
|
|
15
|
+
pythia_skills/plsql-apply/SKILL.md,sha256=sF8NHR8huWkPEXpl0-weIXSjakTnxL9eCH6XvkbxHjQ,6513
|
|
16
|
+
pythia_skills/plsql-explore/SKILL.md,sha256=VuE3QSON29lBQllXG_lKZgviR2BVMo0tzyZ3A1MYS1s,2891
|
|
17
|
+
pythia_skills/plsql-explore/reference/data-dictionary.md,sha256=DnpaPq6ukHnwFMaAuc8vVOz6PKhGIsc3RzRE_KVpyf8,2560
|
|
18
|
+
pythia_skills/plsql-impact/SKILL.md,sha256=85sPgPahXX_YaolZpBjcp5RFtUKWPBLQ8ve7FoebsXg,2468
|
|
19
|
+
pythia_skills/plsql-review/SKILL.md,sha256=w3Cfg4KRI6ziiHz_Es4MHlJAs4p5nZC0a-5Docp_FYc,2356
|
|
20
|
+
pythia_skills/plsql-review/reference/antipatterns.md,sha256=I2s9f6GKiwQ0l0FU8Ifj-CqMT2Z4ZY4GygH62PVWkks,3213
|
|
21
|
+
pythia_skills/plsql-setup/SKILL.md,sha256=rNr3SFw1HaxJAdiFgU0iDJ__lfoobuh9oVYCOWAMGmE,3489
|
|
22
|
+
pythia_skills/plsql-skill-author/SKILL.md,sha256=pG_qRTktVzEfEEniziJtf6w-qMSfi8XVOif221uxGnE,4594
|
|
23
|
+
pythia_skills/plsql-write/SKILL.md,sha256=PNeFTd6UU3c2ni614nN7bdQWTmvmoQduQ4Bf04HC4eU,2644
|
|
24
|
+
pythia_skills/plsql-write/reference/patterns.md,sha256=1p5-GTGpaDeSrHPSEkWf4vCaUGREzQ3F-P67uXj4eBo,2812
|
|
25
|
+
pythia_plsql-0.1.0.dist-info/METADATA,sha256=BeQ9ZdOvdpugKIooUFtuV73CdGLafbM2OtXEkOIQrGQ,8130
|
|
26
|
+
pythia_plsql-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
27
|
+
pythia_plsql-0.1.0.dist-info/entry_points.txt,sha256=dUdl60jlLUfdd4utUcbQruuHgxron7LMmWvxm_SkGFg,39
|
|
28
|
+
pythia_plsql-0.1.0.dist-info/top_level.txt,sha256=5a6jYMFVXa2nyT6jPP8WAbgKAC2qYfRw1PvAyDzQH-E,36
|
|
29
|
+
pythia_plsql-0.1.0.dist-info/RECORD,,
|
|
@@ -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,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
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plsql-apply
|
|
3
|
+
description: Use when a PL/SQL change is ready to reach the database - applying a CREATE OR REPLACE, restoring from the journal, or any other write. Runs the six-step flow through pythia apply and enforces the gate - the developer sees the preview and approves in chat before anything is written, and a broken result is never reported as success.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Applying PL/SQL Changes
|
|
7
|
+
|
|
8
|
+
**Announce at start:** "Using plsql-apply — I'll preview the change first."
|
|
9
|
+
|
|
10
|
+
DDL in Oracle commits itself. There is no transaction to roll back — the
|
|
11
|
+
snapshot pythia takes before writing is the only undo that exists. This skill
|
|
12
|
+
exists so that safety net is always used, and used honestly.
|
|
13
|
+
|
|
14
|
+
## The Iron Law
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
NO WRITE THE DEVELOPER HAS NOT SEEN AND APPROVED
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Applies to every write: new objects, fixes, restores, batch runs. No
|
|
21
|
+
exceptions for "trivial" changes — a one-line change can invalidate twelve
|
|
22
|
+
dependents.
|
|
23
|
+
|
|
24
|
+
## The Workflow
|
|
25
|
+
|
|
26
|
+
**Before step 1:** if this conversation has not yet seen a standalone impact
|
|
27
|
+
analysis for this object, run `plsql-impact` first. The `impact:` line inside
|
|
28
|
+
apply's preview is confirmation of a number you already knew — if it is the
|
|
29
|
+
first time anyone sees it, a step was skipped.
|
|
30
|
+
|
|
31
|
+
1. **Preview.** Run `pythia apply <file>`. This writes nothing: it snapshots,
|
|
32
|
+
computes impact, prints a diff, a warning block, and a confirm token.
|
|
33
|
+
2. **Relay the preview to the developer — verbatim.** Show the diff, the
|
|
34
|
+
`impact:` line, and any `!` warning exactly as printed. Do not summarize
|
|
35
|
+
the diff away; the developer approves what they see, not your paraphrase.
|
|
36
|
+
3. **Wait for an explicit yes.** A yes is an instruction to proceed with THIS
|
|
37
|
+
preview: "yes, apply it", "go ahead", "looks good — do it". Not a yes: a
|
|
38
|
+
compliment without a go-ahead, a question, silence, or an approval that
|
|
39
|
+
was given for an earlier preview. If the developer changes the file
|
|
40
|
+
instead, start over at step 1.
|
|
41
|
+
4. **Apply** by running the exact `To apply:` command pythia printed (it
|
|
42
|
+
contains the token). If pythia says the token is stale, the file or the
|
|
43
|
+
database changed since the preview — go back to step 1, never "retry".
|
|
44
|
+
If the fresh preview's before-side no longer matches what you last saw,
|
|
45
|
+
say so explicitly: someone else may have changed the object on this
|
|
46
|
+
shared database, and the developer must know that before approving.
|
|
47
|
+
5. **Read the exit code — it is the verdict:**
|
|
48
|
+
|
|
49
|
+
| Exit | Meaning | What you must do |
|
|
50
|
+
|------|---------|-----------------|
|
|
51
|
+
| 0 | applied, compiled clean, nothing newly INVALID | report done, mention the restore id |
|
|
52
|
+
| 1 | refused (policy, classification, stale token) | relay the printed reason and its fix; do not work around it |
|
|
53
|
+
| 3 | **written but broken** — compile errors or other objects now INVALID | see below |
|
|
54
|
+
6. **On exit 3, never report success.** Say plainly that the change went in
|
|
55
|
+
and broke something, show the compile errors (line:col) and the list of
|
|
56
|
+
newly INVALID objects, and offer the `To undo:` command pythia printed.
|
|
57
|
+
Fixing forward is allowed only after the developer sees this state.
|
|
58
|
+
|
|
59
|
+
## Restores
|
|
60
|
+
|
|
61
|
+
`pythia journal restore <id>` is itself a write and goes through the same six
|
|
62
|
+
steps and the same gate: preview the reverse diff to the developer, wait for
|
|
63
|
+
yes, then confirm. Note: restoring an object that did not exist before means
|
|
64
|
+
DROP — policy will refuse it under `structural: deny`, and that refusal is
|
|
65
|
+
correct; relay it instead of forcing a way around.
|
|
66
|
+
|
|
67
|
+
## Batch mode
|
|
68
|
+
|
|
69
|
+
`--yes` skips the pause, not the preview — output and journal are identical.
|
|
70
|
+
Use it only when the developer explicitly asked for unattended application
|
|
71
|
+
("apply all of these"). A frustrated "stop asking" grants `--yes` for the
|
|
72
|
+
task at hand, not from now on: confirm the scope once ("this batch, or
|
|
73
|
+
standing?") and default to this-batch-only. A standing `--yes` never extends
|
|
74
|
+
to restores. Rules for a batch:
|
|
75
|
+
|
|
76
|
+
- **Stop at the first exit 3.** Never keep applying onto a broken state.
|
|
77
|
+
- Afterwards report: one line per success, full detail (errors, newly
|
|
78
|
+
INVALID, restore command) for the failure, and the exact list of files
|
|
79
|
+
that were NOT applied because the batch stopped.
|
|
80
|
+
|
|
81
|
+
## Never bypass the write path
|
|
82
|
+
|
|
83
|
+
When `pythia apply` is available, do not write through anything else — not
|
|
84
|
+
SQLcl MCP `run-sql`, not `sqlplus`, not a driver script. Those paths have no
|
|
85
|
+
snapshot, no impact preview, no verify, no journal. If apply refuses a
|
|
86
|
+
statement, that refusal is information for the developer, not an obstacle to
|
|
87
|
+
route around.
|
|
88
|
+
|
|
89
|
+
## Is rollback real? Be honest about it
|
|
90
|
+
|
|
91
|
+
| Group | Is rollback real? |
|
|
92
|
+
|---|---|
|
|
93
|
+
| `plsql_source` | **Yes — completely.** The source is recoverable from `ALL_SOURCE`. |
|
|
94
|
+
| `data_dml` | **No.** After commit only Flashback Query remains, and only within undo retention. |
|
|
95
|
+
| `structural` | **Almost never.** `DROP COLUMN` is permanent; a dropped table may be in the Recycle Bin. |
|
|
96
|
+
| `grants` | Yes, but by hand. |
|
|
97
|
+
| `session` | Not needed. |
|
|
98
|
+
|
|
99
|
+
Never promise "we can always roll back" — that sentence is only true for the
|
|
100
|
+
first row, and saying it generally misleads the developer at the exact moment
|
|
101
|
+
the stakes are highest.
|
|
102
|
+
|
|
103
|
+
## Red Flags — STOP if you catch yourself thinking
|
|
104
|
+
|
|
105
|
+
| Thought | Reality |
|
|
106
|
+
|---------|---------|
|
|
107
|
+
| "It's a tiny change, skip the preview" | Tiny changes invalidate dependents too. Preview. |
|
|
108
|
+
| "The dev approved something like this earlier" | Approval is per-preview, not per-topic. Ask again. |
|
|
109
|
+
| "Exit 3, but my part compiled — report done" | Something is broken that was not. That is not done. |
|
|
110
|
+
| "Token is stale, I'll just take the new one" | The content changed. The developer must see the new preview. |
|
|
111
|
+
| "apply refused it; run-sql will take it" | The refusal is the product working. Relay it. |
|
|
112
|
+
| "I'll restore quietly to clean up my mistake" | Restores are writes. Same gate, same visibility. |
|
|
113
|
+
| "The dev said 'stop asking' once" | That covered that task, not forever. Re-confirm scope on the next one. |
|
|
114
|
+
|
|
115
|
+
## When NOT to use this skill
|
|
116
|
+
|
|
117
|
+
- Reading or exploring — use `plsql-explore`.
|
|
118
|
+
- Judging blast radius before editing — use `plsql-impact` (always run it
|
|
119
|
+
before proposing a change; apply's preview is confirmation, not discovery).
|
|
120
|
+
- Editing files the developer has not asked to land on the database yet.
|
|
121
|
+
|
|
122
|
+
> Invocation note: examples say `pythia ...`; run it however this project
|
|
123
|
+
> provides it (for example `python scripts/pythia.py ...`). Every pythia
|
|
124
|
+
> output prints follow-up commands in the correct form — prefer pasting those.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plsql-explore
|
|
3
|
+
description: Use when you need to understand anything in an Oracle schema - finding objects, reading PL/SQL source, signatures, table columns, DDL, searching code, or asking who uses what. The database is the only source of truth; repo dumps and exports drift and lie.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Exploring the Schema
|
|
7
|
+
|
|
8
|
+
**Announce at start:** "Using plsql-explore — asking the database directly."
|
|
9
|
+
|
|
10
|
+
## The principle: ask the database, never the dump
|
|
11
|
+
|
|
12
|
+
Repositories of exported `.sql` files go stale the day after export. A real
|
|
13
|
+
mid-size system, audited in 2026, compared its repo dump against the live
|
|
14
|
+
database:
|
|
15
|
+
|
|
16
|
+
| Object type | In the dump | In the database | Verdict |
|
|
17
|
+
|---|---|---|---|
|
|
18
|
+
| Procedures | 3,827 | 3,827 | matched |
|
|
19
|
+
| Tables | 952 | 952 | matched |
|
|
20
|
+
| **Types** | **0** | **115** | **all missing** |
|
|
21
|
+
| **Packages** | **0** | **9** | **all missing** |
|
|
22
|
+
| **Indexes** | **116** | **1,016** | **~89% missing** |
|
|
23
|
+
|
|
24
|
+
Code that "reads fine" against the dump can reference types and packages the
|
|
25
|
+
dump never heard of. Read files only when the database is unreachable, or to
|
|
26
|
+
compare a repo version against the live one.
|
|
27
|
+
|
|
28
|
+
## What you need → what you run
|
|
29
|
+
|
|
30
|
+
| Need | Command |
|
|
31
|
+
|---|---|
|
|
32
|
+
| Is the connection alive, what schema | `pythia check` |
|
|
33
|
+
| Find objects by name | `pythia ls "PKG_%"` |
|
|
34
|
+
| Read source, with the compiler's line numbers | `pythia src NAME` (`--body`, `--spec`) |
|
|
35
|
+
| A procedure/function signature | `pythia args NAME` |
|
|
36
|
+
| Columns and real data types | `pythia cols TABLE_NAME` |
|
|
37
|
+
| Full DDL | `pythia ddl TABLE NAME` |
|
|
38
|
+
| Search all PL/SQL text | `pythia grep "text"` |
|
|
39
|
+
| What an object depends on | `pythia deps NAME` |
|
|
40
|
+
| What depends on an object | `pythia impact NAME` |
|
|
41
|
+
| Exact identifier usages (beats grep) | `pythia plscope NAME` |
|
|
42
|
+
| Programs named like this one | `pythia similar NAME` |
|
|
43
|
+
| Everything currently broken | `pythia invalid`, `pythia errors` |
|
|
44
|
+
| A free-form question | `pythia sql "select ..."` (SELECT/WITH only) |
|
|
45
|
+
|
|
46
|
+
## Rules that keep answers honest
|
|
47
|
+
|
|
48
|
+
- **Truncation is always announced.** Outputs end with `-- truncated ...` or
|
|
49
|
+
set `"truncated": true` in `--json`. If you do not see the marker, you saw
|
|
50
|
+
everything; if you do, say so or fetch more (`--limit`, `--offset`,
|
|
51
|
+
`--max-lines`) — never present a truncated list as complete.
|
|
52
|
+
- **`plscope` before `grep`** for "where is X used": PL/Scope is recorded by
|
|
53
|
+
the compiler and exact; grep matches comments and look-alike names. If
|
|
54
|
+
PL/Scope has no data, the command says so and grep is the fallback.
|
|
55
|
+
- **`src` line numbers are the compiler's own** — an error at `line 47`
|
|
56
|
+
means line 47 in `src` output. No offset arithmetic.
|
|
57
|
+
- Default output caps exist to protect your context window; raise them only
|
|
58
|
+
for the object you are actually working on.
|
|
59
|
+
|
|
60
|
+
Deeper reference — which dictionary views back these commands, PL/Scope
|
|
61
|
+
enablement, licensing boundaries: `reference/data-dictionary.md`.
|