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,61 @@
|
|
|
1
|
+
# Data dictionary reference
|
|
2
|
+
|
|
3
|
+
Which Oracle views back each pythia command, and what to know when going
|
|
4
|
+
beyond them with `pythia sql`.
|
|
5
|
+
|
|
6
|
+
## Views behind the commands
|
|
7
|
+
|
|
8
|
+
| Question | View(s) | pythia command |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| What objects exist, status, last change | `ALL_OBJECTS` | `ls`, `invalid`, `similar` |
|
|
11
|
+
| PL/SQL source, line-exact | `ALL_SOURCE` | `src`, and the apply snapshot |
|
|
12
|
+
| Compile errors with line:column | `ALL_ERRORS` | `errors` |
|
|
13
|
+
| Procedure/function signatures | `ALL_ARGUMENTS` | `args` |
|
|
14
|
+
| Columns, types, nullability, defaults | `ALL_TAB_COLUMNS` | `cols` |
|
|
15
|
+
| Object-level dependency graph | `ALL_DEPENDENCIES` | `deps`, `impact` |
|
|
16
|
+
| Identifier declarations and usages | `ALL_IDENTIFIERS` (PL/Scope) | `plscope` |
|
|
17
|
+
| SQL statements inside PL/SQL, per table | `ALL_STATEMENTS` (PL/Scope) | `plscope` on a table |
|
|
18
|
+
| DDL reconstruction | `DBMS_METADATA.GET_DDL` | `ddl` |
|
|
19
|
+
| Session's dangerous privileges | `SESSION_PRIVS` | `check` warning |
|
|
20
|
+
|
|
21
|
+
`ALL_*` views show what the connected user has rights on. Empty results can
|
|
22
|
+
mean "does not exist" or "not visible to this user" — with a least-privilege
|
|
23
|
+
setup, prefer the proxy connection so visibility matches the schema owner's.
|
|
24
|
+
|
|
25
|
+
## PL/Scope
|
|
26
|
+
|
|
27
|
+
PL/Scope data exists only for objects compiled while it was enabled:
|
|
28
|
+
|
|
29
|
+
```sql
|
|
30
|
+
ALTER SESSION SET plscope_settings = 'IDENTIFIERS:ALL, STATEMENTS:ALL';
|
|
31
|
+
ALTER PROCEDURE <name> COMPILE;
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- Statement capture (`ALL_STATEMENTS`) needs Oracle 12.2+.
|
|
35
|
+
- Recompiling objects on a **shared** schema affects everyone using it —
|
|
36
|
+
agree it with the team first. pythia never runs these for you.
|
|
37
|
+
- Check what an object was compiled with: `ALL_PLSQL_OBJECT_SETTINGS`
|
|
38
|
+
(`PLSCOPE_SETTINGS` column).
|
|
39
|
+
|
|
40
|
+
## DBMS_METADATA notes
|
|
41
|
+
|
|
42
|
+
`ddl` disables `STORAGE` and `SEGMENT_ATTRIBUTES` transforms deliberately:
|
|
43
|
+
segment clauses are noise for code review and burn context. If you need
|
|
44
|
+
tablespace/storage detail, ask with `pythia sql` against `DBA_/ALL_SEGMENTS`
|
|
45
|
+
(subject to privileges).
|
|
46
|
+
|
|
47
|
+
## Licensing boundary — stay on the free side by default
|
|
48
|
+
|
|
49
|
+
Safe on every edition, no extra license:
|
|
50
|
+
|
|
51
|
+
- All `ALL_*` / `USER_*` dictionary views used above
|
|
52
|
+
- `V$SESSION`, `EXPLAIN PLAN`, Statspack
|
|
53
|
+
|
|
54
|
+
**Extra-cost** — do not query these unless the site confirms the license:
|
|
55
|
+
|
|
56
|
+
- `DBA_HIST_*` (AWR) — requires Diagnostics Pack
|
|
57
|
+
- SQL Performance Analyzer / SQL Tuning Advisor — Tuning/RAT packs
|
|
58
|
+
|
|
59
|
+
pythia's built-in queries are license-safe. When writing free-form `sql`,
|
|
60
|
+
keep to the free list unless told otherwise — a senior DBA reads restraint
|
|
61
|
+
here as a sign the tooling understands Oracle.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plsql-impact
|
|
3
|
+
description: Use before proposing or writing any change to an Oracle object - a procedure, package, function, trigger, view, or table. Impact analysis comes first, because what depends on an object decides how careful the change must be, and Oracle invalidates dependents in cascade.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Impact Before Change
|
|
7
|
+
|
|
8
|
+
**Announce at start:** "Using plsql-impact to measure the blast radius first."
|
|
9
|
+
|
|
10
|
+
Changing an Oracle object recompiles or invalidates everything that depends
|
|
11
|
+
on it — immediately, schema-wide, for every user of a shared database. The
|
|
12
|
+
cost of knowing first is one command.
|
|
13
|
+
|
|
14
|
+
## The Iron Law
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
NO CHANGE PROPOSED WITHOUT ITS IMPACT MEASURED FIRST
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## The Workflow
|
|
21
|
+
|
|
22
|
+
1. `pythia impact <OBJECT> --depth 2` — everything that depends on it,
|
|
23
|
+
as a tree, ending with the line that matters:
|
|
24
|
+
`-- impact: N dependent objects, M currently VALID`.
|
|
25
|
+
2. `pythia deps <OBJECT> --depth 2` — the other direction, what it uses;
|
|
26
|
+
read it when the change touches calls or table access.
|
|
27
|
+
3. `pythia invalid` — the baseline. Anything already INVALID before the
|
|
28
|
+
change must not be blamed on the change later; apply compares against
|
|
29
|
+
this automatically, but you should know the starting state too.
|
|
30
|
+
|
|
31
|
+
## Reading the numbers
|
|
32
|
+
|
|
33
|
+
| Result | What to do |
|
|
34
|
+
|---|---|
|
|
35
|
+
| 0 dependents | Say so and proceed; verify after apply anyway. |
|
|
36
|
+
| 1–9 dependents | List them to the developer alongside the proposal. |
|
|
37
|
+
| 10+ dependents, or any cross-schema dependent | Show the tree and get an explicit go-ahead **before writing any code**. |
|
|
38
|
+
| Dependents already INVALID | Point them out — the area is already unstable. |
|
|
39
|
+
|
|
40
|
+
Tables deserve the same treatment as code: `impact` on a table shows every
|
|
41
|
+
program that would be invalidated by an `ALTER`.
|
|
42
|
+
|
|
43
|
+
## Red Flags — STOP if you catch yourself thinking
|
|
44
|
+
|
|
45
|
+
| Thought | Reality |
|
|
46
|
+
|---------|---------|
|
|
47
|
+
| "It's just a small helper" | Helpers are the most-depended-on objects there are. |
|
|
48
|
+
| "I'll check impact after writing the code" | Then the number cannot change the design. Too late. |
|
|
49
|
+
| "The preview in apply shows impact anyway" | That line is confirmation of a number you already knew — not discovery. |
|
|
50
|
+
| "It's a new object, nothing depends on it" | True — say that, with `impact` output as evidence, not as an assumption. |
|
|
51
|
+
|
|
52
|
+
## Hand-off
|
|
53
|
+
|
|
54
|
+
Impact known and acceptable → `plsql-write` to write the change following
|
|
55
|
+
the codebase's conventions → `plsql-apply` to land it with preview and
|
|
56
|
+
verification.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plsql-review
|
|
3
|
+
description: Use when reviewing PL/SQL - a changed procedure or package, a proposed file, or an object suspected of causing trouble. Combines the database's own correctness signals with the antipattern checklist, and reports findings anchored to line numbers.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Reviewing PL/SQL
|
|
7
|
+
|
|
8
|
+
**Announce at start:** "Using plsql-review — checking the database's signals first."
|
|
9
|
+
|
|
10
|
+
Review in two passes: what the database *knows* is wrong, then what the
|
|
11
|
+
checklist says is *likely* wrong. Machine signals first — they are free and
|
|
12
|
+
exact.
|
|
13
|
+
|
|
14
|
+
## Pass 1 — the database's own verdict
|
|
15
|
+
|
|
16
|
+
1. `pythia errors NAME` — compile errors and warnings with line:column.
|
|
17
|
+
An object that does not compile needs no style review yet.
|
|
18
|
+
2. `pythia src NAME` — read the source with the compiler's line numbers, so
|
|
19
|
+
findings can be anchored (`line 47: ...`).
|
|
20
|
+
3. `pythia impact NAME --depth 2` — how exposed is this object; a finding in
|
|
21
|
+
something with 40 dependents outranks the same finding in a leaf.
|
|
22
|
+
4. For a proposed file (not yet applied): the compile verdict arrives at
|
|
23
|
+
apply time — say explicitly that compilation is still unverified.
|
|
24
|
+
|
|
25
|
+
## Pass 2 — the antipattern checklist
|
|
26
|
+
|
|
27
|
+
Work through `reference/antipatterns.md` — and the project's own
|
|
28
|
+
`.pythia/conventions.md` when it exists, which outranks the generic list.
|
|
29
|
+
The seven entries, each with
|
|
30
|
+
wrong → right → why: row-by-row cursor loops, string-concatenated dynamic
|
|
31
|
+
SQL, `WHEN OTHERS THEN NULL`, `COMMIT` inside loops, hand-copied types
|
|
32
|
+
instead of `%TYPE`/`%ROWTYPE`, large OUT parameters without `NOCOPY`, and
|
|
33
|
+
convention drift against the codebase (`pythia similar` shows the house
|
|
34
|
+
style).
|
|
35
|
+
|
|
36
|
+
## Reporting findings
|
|
37
|
+
|
|
38
|
+
- Anchor every finding: `line N: <what> — <why it bites> — <the fix>`.
|
|
39
|
+
- Severity order: breaks correctness → silently loses data or errors →
|
|
40
|
+
performance at scale → style drift.
|
|
41
|
+
- Verify the claim before writing it: read the actual lines with `src`;
|
|
42
|
+
never report from memory of the diff alone.
|
|
43
|
+
- A clean review says what was checked, not just "looks good": compiles
|
|
44
|
+
clean, no new INVALID, checklist passed.
|
|
45
|
+
|
|
46
|
+
## When NOT to use this skill
|
|
47
|
+
|
|
48
|
+
- Reviewing whether a change is *safe to apply* — that is `plsql-impact`
|
|
49
|
+
plus `plsql-apply`'s preview; this skill judges the code itself.
|
|
50
|
+
- Reviewing non-PL/SQL application code — outside this skill's scope.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# PL/SQL antipatterns
|
|
2
|
+
|
|
3
|
+
Seven findings that recur in real codebases. Each: how it looks, what to
|
|
4
|
+
write instead, and why it bites. Anchor findings to line numbers from
|
|
5
|
+
`pythia src`.
|
|
6
|
+
|
|
7
|
+
## 1. Row-by-row cursor loop doing DML
|
|
8
|
+
|
|
9
|
+
**Wrong**
|
|
10
|
+
```sql
|
|
11
|
+
FOR r IN (SELECT id FROM t_order WHERE status = 'NEW') LOOP
|
|
12
|
+
UPDATE t_order SET status = 'DONE' WHERE id = r.id;
|
|
13
|
+
END LOOP;
|
|
14
|
+
```
|
|
15
|
+
**Right** — `BULK COLLECT ... LIMIT` + `FORALL` (see patterns.md for the
|
|
16
|
+
full template), or better: one set-based `UPDATE` when no per-row logic
|
|
17
|
+
exists.
|
|
18
|
+
**Why** — a context switch per row; thousands of rows means thousands of
|
|
19
|
+
switches. The set-based form is also atomic.
|
|
20
|
+
|
|
21
|
+
## 2. Dynamic SQL built by concatenation
|
|
22
|
+
|
|
23
|
+
**Wrong**
|
|
24
|
+
```sql
|
|
25
|
+
EXECUTE IMMEDIATE 'DELETE FROM t_log WHERE id = ' || p_id;
|
|
26
|
+
```
|
|
27
|
+
**Right**
|
|
28
|
+
```sql
|
|
29
|
+
EXECUTE IMMEDIATE 'DELETE FROM t_log WHERE id = :1' USING p_id;
|
|
30
|
+
```
|
|
31
|
+
**Why** — SQL injection when the value is user-reachable, and a hard parse
|
|
32
|
+
per distinct value even when it is not: shared-pool churn that hits the
|
|
33
|
+
whole instance, not just this session.
|
|
34
|
+
|
|
35
|
+
## 3. `WHEN OTHERS THEN NULL`
|
|
36
|
+
|
|
37
|
+
**Wrong**
|
|
38
|
+
```sql
|
|
39
|
+
EXCEPTION WHEN OTHERS THEN NULL;
|
|
40
|
+
```
|
|
41
|
+
**Right** — handle the exceptions you can name; for the rest, log and
|
|
42
|
+
`RAISE`.
|
|
43
|
+
**Why** — every future bug in the block becomes silent wrong data. The
|
|
44
|
+
worst version is around a `SELECT INTO`, where it also hides
|
|
45
|
+
`TOO_MANY_ROWS` — a data-quality alarm.
|
|
46
|
+
|
|
47
|
+
## 4. `COMMIT` inside a loop
|
|
48
|
+
|
|
49
|
+
**Wrong**
|
|
50
|
+
```sql
|
|
51
|
+
FOR r IN c LOOP
|
|
52
|
+
process(r);
|
|
53
|
+
COMMIT; -- "to be safe"
|
|
54
|
+
END LOOP;
|
|
55
|
+
```
|
|
56
|
+
**Right** — commit once, at the transaction's owner (usually the outermost
|
|
57
|
+
caller). For huge volumes, batch commits at a documented interval are a
|
|
58
|
+
deliberate, named decision — not a reflex.
|
|
59
|
+
**Why** — a failure mid-loop leaves a half-applied state that can be
|
|
60
|
+
neither completed nor rolled back; it also breaks any caller that thought
|
|
61
|
+
it owned the transaction, and `ORA-01555` risk goes up, not down.
|
|
62
|
+
|
|
63
|
+
## 5. Hand-copied types instead of `%TYPE` / `%ROWTYPE`
|
|
64
|
+
|
|
65
|
+
**Wrong**
|
|
66
|
+
```sql
|
|
67
|
+
v_name VARCHAR2(50); -- the column is VARCHAR2(100) since 2024
|
|
68
|
+
```
|
|
69
|
+
**Right**
|
|
70
|
+
```sql
|
|
71
|
+
v_name customers.name%TYPE;
|
|
72
|
+
```
|
|
73
|
+
**Why** — the declaration is a snapshot that silently drifts from the
|
|
74
|
+
schema; the failure arrives later as `VALUE_ERROR` on production data.
|
|
75
|
+
|
|
76
|
+
## 6. Large OUT parameters without `NOCOPY`
|
|
77
|
+
|
|
78
|
+
**Wrong**
|
|
79
|
+
```sql
|
|
80
|
+
PROCEDURE render(p_out IN OUT CLOB);
|
|
81
|
+
```
|
|
82
|
+
**Right**
|
|
83
|
+
```sql
|
|
84
|
+
PROCEDURE render(p_out IN OUT NOCOPY CLOB);
|
|
85
|
+
```
|
|
86
|
+
**Why** — IN OUT copies on entry and exit; for CLOBs and big collections
|
|
87
|
+
that is real memory and time per call.
|
|
88
|
+
|
|
89
|
+
## 7. Style drift from the codebase
|
|
90
|
+
|
|
91
|
+
**Wrong** — new naming scheme, new cursor style, new comment format,
|
|
92
|
+
introduced silently in one procedure.
|
|
93
|
+
**Right** — `pythia similar` + `pythia src` on the top hits; match them.
|
|
94
|
+
Propose style improvements to the developer as a separate conversation.
|
|
95
|
+
**Why** — a mixed-style codebase costs every future reader; consistency is
|
|
96
|
+
a feature maintainers can feel.
|
|
97
|
+
|
|
98
|
+
## Reporting format
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
line 47: WHEN OTHERS THEN NULL — swallows every error including
|
|
102
|
+
TOO_MANY_ROWS — handle NO_DATA_FOUND explicitly, log and RAISE the rest
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Severity order: correctness → silent data/error loss → performance at
|
|
106
|
+
scale → style.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plsql-setup
|
|
3
|
+
description: Use when setting pythia up for a project or a machine - writing connections.json, creating a least-privilege agent user, wiring the SQLcl MCP server, or diagnosing a connection that will not open. Also the place to start when check prints a privilege warning.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Setting Up
|
|
7
|
+
|
|
8
|
+
**Announce at start:** "Using plsql-setup to configure the database access."
|
|
9
|
+
|
|
10
|
+
Set up in this order: connection first (everything else needs it), the
|
|
11
|
+
least-privilege user second (the only protection that cannot be bypassed),
|
|
12
|
+
SQLcl MCP last (optional, reads only).
|
|
13
|
+
|
|
14
|
+
## 1. Connection
|
|
15
|
+
|
|
16
|
+
Create `.pythia/connections.json` at the project root — `pythia install`
|
|
17
|
+
scaffolds it (pip installs: `pip install pythia-plsql`), or copy
|
|
18
|
+
`examples/connections.example.json` from a clone. Fill it in. Rules pythia
|
|
19
|
+
applies:
|
|
20
|
+
|
|
21
|
+
- One entry: used as-is. Several entries: the path segment directly under the
|
|
22
|
+
project root picks one (`root/DEV/...` → `DEV`), else the entry named by a
|
|
23
|
+
top-level `"default": "<name>"`. Ambiguity is an error, never a guess.
|
|
24
|
+
- `--conn NAME` and `PYTHIA_CONNECTION` override everything; the
|
|
25
|
+
`PYTHIA_USER/PYTHIA_PASSWORD/PYTHIA_DSN` variables bypass the file.
|
|
26
|
+
- The file holds credentials: it is gitignored — keep it that way, and keep
|
|
27
|
+
it out of chat and screenshots.
|
|
28
|
+
|
|
29
|
+
Verify with `pythia check`: it prints who you are connected as and object
|
|
30
|
+
counts. A failure names the connection and what to check.
|
|
31
|
+
|
|
32
|
+
## 2. The agent's database user — the real protection
|
|
33
|
+
|
|
34
|
+
The policy file is an application-side fence; **Oracle grants are the only
|
|
35
|
+
layer an agent cannot walk around.** Oracle has no clean per-object form of
|
|
36
|
+
"may edit PL/SQL in that schema" — compiling into another schema needs
|
|
37
|
+
`CREATE ANY PROCEDURE`, which spans every schema on the instance.
|
|
38
|
+
|
|
39
|
+
The workable pattern is **proxy authentication**: a logon-only user that
|
|
40
|
+
connects *through* the schema owner. The agent never learns the owner's
|
|
41
|
+
password, revocation is one statement, the audit trail shows who really
|
|
42
|
+
connected, and the blast radius is the one development schema.
|
|
43
|
+
|
|
44
|
+
Run `examples/agent-user-setup.example.sql` (as a DBA, names adapted), then
|
|
45
|
+
set the connection's user to `"agent_user[schema_owner]"`.
|
|
46
|
+
|
|
47
|
+
Oracle's own guidance for LLM access, follow it: grant minimum privileges,
|
|
48
|
+
never point an LLM at a production database, audit its activity regularly.
|
|
49
|
+
|
|
50
|
+
`pythia check` warns on one line when the session holds `%ANY%` privileges or
|
|
51
|
+
runs as the schema owner directly. The goal state is: no warning.
|
|
52
|
+
|
|
53
|
+
## 3. SQLcl MCP server (optional, reads only)
|
|
54
|
+
|
|
55
|
+
If SQLcl 25.2+ is installed, agents can read through Oracle's official MCP
|
|
56
|
+
server: command `sql -mcp`. Example client config:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{"mcpServers": {"sqlcl": {"command": "sql", "args": ["-mcp"]}}}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
- Keep the default restrict level (`-R 4`, most restrictive): it blocks host
|
|
63
|
+
commands and `@` scripts. Note it does NOT block DML/DDL inside `run-sql` —
|
|
64
|
+
which is why **writes never go through MCP**: only `pythia apply` has the
|
|
65
|
+
snapshot, preview, verify and journal.
|
|
66
|
+
- Built-in audit, worth telling the DBA about: every interaction lands in
|
|
67
|
+
`DBTOOLS$MCP_LOG`; `V$SESSION.MODULE` shows the MCP client and
|
|
68
|
+
`V$SESSION.ACTION` the LLM's name; generated SQL carries an
|
|
69
|
+
`/* LLM in use */` comment.
|
|
70
|
+
|
|
71
|
+
## Done when
|
|
72
|
+
|
|
73
|
+
- `pythia check` connects, shows the right schema, and prints **no**
|
|
74
|
+
privilege warning.
|
|
75
|
+
- `pythia policy` prints the write policy and the rollback table.
|
|
76
|
+
- The credentials file is untracked (`git status` does not show it).
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plsql-skill-author
|
|
3
|
+
description: Use when the developer wants their own way of working captured as a new skill - "make a skill for how we do X", a house convention or preference worth teaching every future session, a team ritual, or the same correction arriving for the second time. Interviews the developer, mines the real conventions from the database, and writes a skill in this pack's format.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Authoring a New Skill
|
|
7
|
+
|
|
8
|
+
**Announce at start:** "Using plsql-skill-author — let's capture how you actually work."
|
|
9
|
+
|
|
10
|
+
A skill is a decision captured so it never has to be re-argued. Capture what
|
|
11
|
+
the team *actually does* — with evidence from the database — not what anyone
|
|
12
|
+
remembers about it.
|
|
13
|
+
|
|
14
|
+
## Step 1 — Interview, one question at a time
|
|
15
|
+
|
|
16
|
+
Ask, in order, waiting for each answer:
|
|
17
|
+
|
|
18
|
+
1. **What task is this for?» One skill per concern — "our report procedure
|
|
19
|
+
ritual" is one skill; "everything about our team" is not.
|
|
20
|
+
2. **When should it trigger?** Collect the developer's *own words* — the
|
|
21
|
+
phrases they would type ("làm báo cáo", "clone the export proc", an error
|
|
22
|
+
code, a file pattern). These go into the description verbatim; triggering
|
|
23
|
+
lives or dies on them.
|
|
24
|
+
3. **Which parts are law, which are taste?** Hard rules get an Iron Law and
|
|
25
|
+
a red-flags table; preferences get a "default unless told otherwise".
|
|
26
|
+
4. **What does *wrong* look like?** Past incidents make the best red-flag
|
|
27
|
+
rows.
|
|
28
|
+
|
|
29
|
+
## Step 2 — Mine the evidence
|
|
30
|
+
|
|
31
|
+
Memory lies; the schema does not. Before writing a line:
|
|
32
|
+
|
|
33
|
+
- `pythia similar <TYPICAL_NAME>` → which family of programs embodies this
|
|
34
|
+
workflow; open the top hits with `pythia src` and extract the *actual*
|
|
35
|
+
naming, parameter and structure conventions.
|
|
36
|
+
- `pythia args` / `pythia cols` for the signatures and types the skill will
|
|
37
|
+
tell people to use.
|
|
38
|
+
- Save two or three short **verbatim** snippets as examples — real code
|
|
39
|
+
outranks invented code.
|
|
40
|
+
|
|
41
|
+
## Step 3 — Draft in the house format
|
|
42
|
+
|
|
43
|
+
- Frontmatter: kebab-case `name` matching the folder; `description` that
|
|
44
|
+
opens with the trigger condition (`Use when ...`) and contains the
|
|
45
|
+
developer's phrases from step 1.
|
|
46
|
+
- Body budget ~150 lines. Long material (templates, checklists, snippet
|
|
47
|
+
libraries) goes to `reference/` and is linked, not pasted.
|
|
48
|
+
- Structure menu — use what the answers call for, skip the rest:
|
|
49
|
+
Iron Law (one line, caps) · numbered workflow · red-flags table
|
|
50
|
+
("thought → reality") · "When NOT to use" · an **Announce at start** line.
|
|
51
|
+
- Write in the language the team works in; this pack is English, a private
|
|
52
|
+
team skill may be Vietnamese — the developer decides.
|
|
53
|
+
|
|
54
|
+
**Not everything needs a skill.** Pure naming and style rules travel better
|
|
55
|
+
as `.pythia/conventions.json` (machine-checked at every apply preview) plus
|
|
56
|
+
`.pythia/conventions.md` (prose the agent reads). Reserve skills for
|
|
57
|
+
workflows — things with steps, gates and judgment.
|
|
58
|
+
|
|
59
|
+
## Step 4 — Place it
|
|
60
|
+
|
|
61
|
+
User skills live in the **developer's project**, e.g.
|
|
62
|
+
`.claude/skills/<name>/SKILL.md` for Claude Code (other agents: the layout
|
|
63
|
+
`skills/<name>/SKILL.md` works with `npx skills add`). Never write into the
|
|
64
|
+
installed pythia pack — updates would overwrite it, and the pack's lint
|
|
65
|
+
enforces its own fixed skill list.
|
|
66
|
+
|
|
67
|
+
## Step 5 — Verify it triggers
|
|
68
|
+
|
|
69
|
+
In a **fresh session**, give a task phrased the way the developer would
|
|
70
|
+
really ask (step 2's phrases). The skill must activate unprompted. If it
|
|
71
|
+
does not, the description is the bug: sharpen it with the exact phrases that
|
|
72
|
+
failed, and test again.
|
|
73
|
+
|
|
74
|
+
## Keep it alive
|
|
75
|
+
|
|
76
|
+
When the developer corrects the agent for the same thing twice, propose
|
|
77
|
+
folding that correction into the skill — that is the skill earning its keep.
|
|
78
|
+
Retire rules that stopped being true; a stale skill is worse than none.
|
|
79
|
+
|
|
80
|
+
## Before sharing outside the team
|
|
81
|
+
|
|
82
|
+
Run the hygiene check this pack applies to itself: no hosts, schema names,
|
|
83
|
+
credentials, or internal identifiers in the skill or its references. What is
|
|
84
|
+
fine in a private repo is a leak in a public one.
|
|
85
|
+
|
|
86
|
+
## Red Flags — STOP if you catch yourself thinking
|
|
87
|
+
|
|
88
|
+
| Thought | Reality |
|
|
89
|
+
|---------|---------|
|
|
90
|
+
| "I'll write it from memory of this chat" | Mine `similar`/`src` first — the codebase is the authority. |
|
|
91
|
+
| "One big skill covering everything" | One concern per skill, or nothing triggers cleanly. |
|
|
92
|
+
| "Paste the whole style guide in" | Budget is ~150 lines; long material goes to reference/. |
|
|
93
|
+
| "The description can be generic" | Generic descriptions never trigger. Use the developer's own phrases. |
|
|
94
|
+
| "It works, no need to test triggering" | Untested triggering = a skill nobody ever sees again. |
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plsql-write
|
|
3
|
+
description: Use when writing or modifying PL/SQL source - a procedure, function, package, trigger, or view - after impact is known. The codebase's conventions already exist; copy them instead of inventing style, and anchor every type to the database's reality.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Writing PL/SQL
|
|
7
|
+
|
|
8
|
+
**Announce at start:** "Using plsql-write — mining the codebase's conventions first."
|
|
9
|
+
|
|
10
|
+
**Before anything:** if the project has `.pythia/conventions.md`, read it —
|
|
11
|
+
house rules there outrank every generic pattern below, and
|
|
12
|
+
`pythia conventions` shows the naming patterns the apply preview will check.
|
|
13
|
+
|
|
14
|
+
A codebase with thousands of procedures has already decided how procedures
|
|
15
|
+
look. Your job is to write one that a maintainer cannot tell from the
|
|
16
|
+
existing ones — not to introduce a better style.
|
|
17
|
+
|
|
18
|
+
## The Workflow
|
|
19
|
+
|
|
20
|
+
1. **Find the models.** `pythia similar <NEW_NAME>` ranks existing programs
|
|
21
|
+
sharing name tokens; the `MATCHED_TOKENS` column says why. Open the top
|
|
22
|
+
two or three with `pythia src` and imitate: naming, parameter prefixes,
|
|
23
|
+
cursor style, error handling, comment style.
|
|
24
|
+
2. **Anchor the signatures.** For every program you call:
|
|
25
|
+
`pythia args NAME` — real parameter names, order, types, defaults. Never
|
|
26
|
+
guess a signature from memory of similar code.
|
|
27
|
+
3. **Anchor the types.** For every table you touch: `pythia cols TABLE` —
|
|
28
|
+
then declare variables with `%TYPE` / `%ROWTYPE` against those columns
|
|
29
|
+
instead of copying the current type by hand. The declaration then
|
|
30
|
+
survives column changes.
|
|
31
|
+
4. **Write the file.** Rules the write path enforces — follow them here:
|
|
32
|
+
- **One object per file.** Package spec and body are two files.
|
|
33
|
+
- End the file with the PL/SQL block's `;` and a final line holding `/`.
|
|
34
|
+
- Name the object unqualified, or qualified with the exact schema the
|
|
35
|
+
connection targets — a mismatch is refused at apply time.
|
|
36
|
+
5. **Check yourself before handing off.** Reread against
|
|
37
|
+
`reference/patterns.md` — cursor and bulk patterns, exception discipline,
|
|
38
|
+
bind variables, commit ownership.
|
|
39
|
+
|
|
40
|
+
## Conventions outrank preferences
|
|
41
|
+
|
|
42
|
+
If the codebase writes explicit cursors where you would write `FOR r IN`,
|
|
43
|
+
write explicit cursors. If its parameter prefixes look dated, use them
|
|
44
|
+
anyway. A mixed-style codebase is worse than a consistently dated one —
|
|
45
|
+
propose style changes to the developer separately, never silently.
|
|
46
|
+
|
|
47
|
+
## When NOT to use this skill
|
|
48
|
+
|
|
49
|
+
- Understanding existing code → `plsql-explore`.
|
|
50
|
+
- Measuring what a change breaks → `plsql-impact` (must already be done).
|
|
51
|
+
- Landing the file on the database → `plsql-apply`, always — never
|
|
52
|
+
`run-sql`, never `sqlplus`.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# PL/SQL patterns worth copying
|
|
2
|
+
|
|
3
|
+
Generic patterns for when the codebase gives no model to imitate. When the
|
|
4
|
+
codebase disagrees with this file, **the codebase wins** — consistency beats
|
|
5
|
+
preference.
|
|
6
|
+
|
|
7
|
+
## Anchor declarations to the dictionary
|
|
8
|
+
|
|
9
|
+
```sql
|
|
10
|
+
-- fragile: copies today's type by hand
|
|
11
|
+
v_customer_name VARCHAR2(100);
|
|
12
|
+
|
|
13
|
+
-- survives column changes
|
|
14
|
+
v_customer_name customers.name%TYPE;
|
|
15
|
+
r_order orders%ROWTYPE;
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Bulk over row-by-row
|
|
19
|
+
|
|
20
|
+
```sql
|
|
21
|
+
-- slow at scale: one context switch per row
|
|
22
|
+
FOR r IN (SELECT id FROM t_order WHERE status = 'NEW') LOOP
|
|
23
|
+
process_order(r.id);
|
|
24
|
+
END LOOP;
|
|
25
|
+
|
|
26
|
+
-- bulk: fetch in batches, write with FORALL
|
|
27
|
+
DECLARE
|
|
28
|
+
TYPE t_ids IS TABLE OF t_order.id%TYPE;
|
|
29
|
+
v_ids t_ids;
|
|
30
|
+
CURSOR c IS SELECT id FROM t_order WHERE status = 'NEW';
|
|
31
|
+
BEGIN
|
|
32
|
+
OPEN c;
|
|
33
|
+
LOOP
|
|
34
|
+
FETCH c BULK COLLECT INTO v_ids LIMIT 500;
|
|
35
|
+
EXIT WHEN v_ids.COUNT = 0;
|
|
36
|
+
FORALL i IN 1 .. v_ids.COUNT
|
|
37
|
+
UPDATE t_order SET status = 'DONE' WHERE id = v_ids(i);
|
|
38
|
+
END LOOP;
|
|
39
|
+
CLOSE c;
|
|
40
|
+
END;
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The `LIMIT` matters: unbounded `BULK COLLECT` trades the row-switch problem
|
|
44
|
+
for a memory problem.
|
|
45
|
+
|
|
46
|
+
## Exceptions: handle what you can name, re-raise the rest
|
|
47
|
+
|
|
48
|
+
```sql
|
|
49
|
+
BEGIN
|
|
50
|
+
...
|
|
51
|
+
EXCEPTION
|
|
52
|
+
WHEN NO_DATA_FOUND THEN
|
|
53
|
+
RETURN NULL; -- a decision, made on purpose
|
|
54
|
+
WHEN OTHERS THEN
|
|
55
|
+
log_error(sqlcode, sqlerrm, 'PKG_ORDER.calc_total');
|
|
56
|
+
RAISE; -- never swallow; the caller must know
|
|
57
|
+
END;
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`WHEN OTHERS` without `RAISE` (or `RAISE_APPLICATION_ERROR`) converts every
|
|
61
|
+
future bug into silent wrong data.
|
|
62
|
+
|
|
63
|
+
## Dynamic SQL: binds, never concatenation
|
|
64
|
+
|
|
65
|
+
```sql
|
|
66
|
+
-- injection + hard parse per call
|
|
67
|
+
EXECUTE IMMEDIATE 'SELECT total FROM t_order WHERE id = ' || p_id INTO v_t;
|
|
68
|
+
|
|
69
|
+
-- shared cursor, safe
|
|
70
|
+
EXECUTE IMMEDIATE 'SELECT total FROM t_order WHERE id = :1'
|
|
71
|
+
INTO v_t USING p_id;
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Identifiers (table names) cannot be bound — validate them against
|
|
75
|
+
`ALL_TABLES`/`ALL_OBJECTS` before splicing, and say so in a comment.
|
|
76
|
+
|
|
77
|
+
## Commit ownership
|
|
78
|
+
|
|
79
|
+
Utility and business procedures do not `COMMIT`; the outermost caller — the
|
|
80
|
+
one that knows the transaction's boundaries — does. A procedure that commits
|
|
81
|
+
mid-loop turns a failed run into a half-applied state nobody can reason
|
|
82
|
+
about, and breaks the caller's ability to roll back.
|
|
83
|
+
|
|
84
|
+
## Large OUT parameters
|
|
85
|
+
|
|
86
|
+
```sql
|
|
87
|
+
PROCEDURE render_report(p_clob IN OUT NOCOPY CLOB);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Without `NOCOPY`, IN OUT copies the value both ways; for big CLOBs and
|
|
91
|
+
collections that is real memory and time. (It is a hint, not a guarantee —
|
|
92
|
+
still worth writing.)
|
|
93
|
+
|
|
94
|
+
## Naming: mine, don't invent
|
|
95
|
+
|
|
96
|
+
Before naming anything: `pythia similar <intended_name>` and copy the
|
|
97
|
+
dominant token order, prefixes and casing of the top hits. Parameter
|
|
98
|
+
prefixes, cursor names, and constant style come from `pythia src` of a
|
|
99
|
+
neighboring program — not from this file.
|