Compare commits

...
15 Commits
33 changed files with 1619 additions and 3 deletions

No files matched your search

+22
View File
@@ -0,0 +1,22 @@
# Agent Guidelines
## Architecture & Modules
- Each tool/service lives in its own top-level folder (`<service>/`) with its own `Justfile`.
- The root `Justfile` registers every service using `mod <service>` and runs `just <service>::deploy` in `all`.
- Deployment links the **entire module folder** directly to its target destination (e.g. `ln -sfnT {{config_dir}} {{dest}}`), rather than linking individual files or subfolders.
## Justfile Philosophy
- Keep `Justfile` recipes declarative, clean, and minimal — **never use bash loops, subshells, or complex inline scripts**.
- Always define paths at the top using `source_directory()` and `env("HOME")`.
- Always set the default recipe to list commands:
```just
@default:
just --list
```
- Every module `Justfile` **must** expose a `deploy` recipe.
## Git & Commit Convention
- Follow Conventional Commits: `<type>(<scope>): <short imperative description>` (or `<type>: <description>` for root-level changes).
- Allowed types: `feat`, `fix`, `refactor`, `chore`, `doc`, `ops`.
- `<scope>` is the module name (`niri`, `xxh`, `agents`, etc.).
- Keep messages lowercase, concise, and without a trailing period (e.g., `feat(agents): add initial skills`, `refactor(xxh): standardize justfile`).
+13
View File
@@ -0,0 +1,13 @@
mod agents
mod niri
mod xxh
@default:
just --list
# Deploy all configurations
all:
just agents::deploy
just niri::deploy
just xxh::deploy
@echo "All dotfiles deployed successfully!"
+37
View File
@@ -0,0 +1,37 @@
# Dotfiles
Modular personal dotfiles managed with [just](https://github.com/casey/just).
## Philosophy
- **Isolation**: Each tool/service has its own self-contained directory with its configuration and local `Justfile`.
- **Modularity**: The root `Justfile` imports each component as a `just` module.
- **Simplicity**: Declarative deployment recipes using symbolic links or build steps.
## Usage
List all available modules and commands:
```sh
just
```
Deploy a specific configuration:
```sh
just <service>::deploy # e.g., just niri::deploy, just xxh::deploy
```
Deploy everything:
```sh
just all
```
## Adding a New Configuration
1. Create a dedicated directory: `<service>/`
2. Place the configuration files inside it.
3. Create `<service>/Justfile` with a `deploy` recipe.
4. Register the module in the root `Justfile`:
```just
mod <service>
```
5. Add `just <service>::deploy` under `@all` in the root `Justfile`.
+18
View File
@@ -0,0 +1,18 @@
# Variables
config_dir := source_directory()
agents_dest := env("HOME") + "/.agents"
@default:
just --list
# Deploy agents configuration
deploy:
@echo "Deploying agents configuration..."
ln -sfnT {{config_dir}} {{agents_dest}}
@echo "Deployment successful!"
# Uninstall agents configuration
uninstall:
@echo "Uninstalling agents configuration..."
rm -rf {{agents_dest}}
@echo "Uninstallation successful!"
@@ -0,0 +1,37 @@
# Deepening
How to deepen a cluster of shallow modules safely, given its dependencies. Assumes the vocabulary in [SKILL.md](SKILL.md): **module**, **interface**, **seam**, **adapter**.
## Dependency categories
When assessing a candidate for deepening, classify its dependencies. The category determines how the deepened module is tested across its seam.
### 1. In-process
Pure computation, in-memory state, no I/O. Always deepenable: merge the modules and test through the new interface directly. No adapter needed.
### 2. Local-substitutable
Dependencies that have local test stand-ins (PGLite for Postgres, in-memory filesystem). Deepenable if the stand-in exists. The deepened module is tested with the stand-in running in the test suite. The seam is internal; no port at the module's external interface.
### 3. Remote but owned (Ports & Adapters)
Your own services across a network boundary (microservices, internal APIs). Define a **port** (interface) at the seam. The deep module owns the logic; the transport is injected as an **adapter**. Tests use an in-memory adapter. Production uses an HTTP/gRPC/queue adapter.
Recommendation shape: *"Define a port at the seam, implement an HTTP adapter for production and an in-memory adapter for testing, so the logic sits in one deep module even though it's deployed across a network."*
### 4. True external (Mock)
Third-party services (Stripe, Twilio, etc.) you don't control. The deepened module takes the external dependency as an injected port; tests provide a mock adapter.
## Seam discipline
- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a port unless at least two adapters are justified (typically production + test). A single-adapter seam is just indirection.
- **Internal seams vs external seams.** A deep module can have internal seams (private to its implementation, used by its own tests) as well as the external seam at its interface. Don't expose internal seams through the interface just because tests use them.
## Testing strategy: replace, don't layer
- Old unit tests on shallow modules become waste once tests at the deepened module's interface exist; delete them.
- Write new tests at the deepened module's interface. The **interface is the test surface**.
- Tests assert on observable outcomes through the interface, not internal state.
- Tests should survive internal refactors, since they describe behaviour, not implementation. If a test has to change when the implementation changes, it's testing past the interface.
@@ -0,0 +1,44 @@
# Design It Twice
When the user wants to explore alternative interfaces for a chosen deepening candidate, use this parallel sub-agent pattern. Based on "Design It Twice" (Ousterhout): your first idea is unlikely to be the best.
Uses the vocabulary in [SKILL.md](SKILL.md): **module**, **interface**, **seam**, **adapter**, **leverage**.
## Process
### 1. Frame the problem space
Before spawning sub-agents, write a user-facing explanation of the problem space for the chosen candidate:
- The constraints any new interface would need to satisfy
- The dependencies it would rely on, and which category they fall into (see [DEEPENING.md](DEEPENING.md))
- A rough illustrative code sketch to ground the constraints, not a proposal, just a way to make the constraints concrete
Show this to the user, then immediately proceed to Step 2. The user reads and thinks while the sub-agents work in parallel.
### 2. Spawn sub-agents
Spawn 3+ sub-agents in parallel. Each must produce a **radically different** interface for the deepened module.
Prompt each sub-agent with a separate technical brief (file paths, coupling details, dependency category from [DEEPENING.md](DEEPENING.md), what sits behind the seam). The brief is independent of the user-facing problem-space explanation in Step 1. Give each agent a different design constraint:
- Agent 1: "Minimize the interface: aim for 1–3 entry points max. Maximise leverage per entry point."
- Agent 2: "Maximise flexibility: support many use cases and extension."
- Agent 3: "Optimise for the most common caller: make the default case trivial."
- Agent 4 (if applicable): "Design around ports & adapters for cross-seam dependencies."
Include both [SKILL.md](SKILL.md) vocabulary and GLOSSARY.md vocabulary in the brief so each sub-agent names things consistently with the architecture language and the project's domain language.
Each sub-agent outputs:
1. Interface (types, methods, params, plus invariants, ordering, error modes)
2. Usage example showing how callers use it
3. What the implementation hides behind the seam
4. Dependency strategy and adapters (see [DEEPENING.md](DEEPENING.md))
5. Trade-offs: where leverage is high, where it's thin
### 3. Present and compare
Present designs sequentially so the user can absorb each one, then compare them in prose. Contrast by **depth** (leverage at the interface), **locality** (where change concentrates), and **seam placement**.
After comparing, give your own recommendation: which design you think is strongest and why. If elements from different designs would combine well, propose a hybrid. Be opinionated: the user wants a strong read, not a menu.
+114
View File
@@ -0,0 +1,114 @@
---
name: codebase-design
description: Shared vocabulary for designing deep modules. Use when the user wants to design or improve a module's interface, find deepening opportunities, decide where a seam goes, make code more testable or AI-navigable, or when another skill needs the deep-module vocabulary.
---
# Codebase Design
Design **deep modules**: a lot of behaviour behind a small interface, placed at a clean seam, testable through that interface. Use this language and these principles wherever code is being designed or restructured. The aim is leverage for callers, locality for maintainers, and testability for everyone.
## Glossary
Use these terms exactly: don't substitute "component," "service," "API," or "boundary." Consistent language is the whole point.
**Module**: anything with an interface and an implementation. Deliberately scale-agnostic: a function, class, package, or tier-spanning slice. _Avoid_: unit, component, service.
**Interface**: everything a caller must know to use the module correctly: the type signature, but also invariants, ordering constraints, error modes, required configuration, and performance characteristics. _Avoid_: API, signature (too narrow, they refer only to the type-level surface).
**Implementation**: what's inside a module, its body of code. Distinct from **Adapter**: a thing can be a small adapter with a large implementation (a Postgres repo) or a large adapter with a small implementation (an in-memory fake). Reach for "adapter" when the seam is the topic; "implementation" otherwise.
**Depth**: leverage at the interface. The amount of behaviour a caller (or test) can exercise per unit of interface they have to learn. A module is **deep** when a large amount of behaviour sits behind a small interface, **shallow** when the interface is nearly as complex as the implementation.
**Seam** _(Michael Feathers)_: a place where you can alter behaviour without editing in that place; the *location* at which a module's interface lives. Where to put the seam is its own design decision, distinct from what goes behind it. _Avoid_: boundary (overloaded with DDD's bounded context).
**Adapter**: a concrete thing that satisfies an interface at a seam. Describes *role* (what slot it fills), not substance (what's inside).
**Leverage**: what callers get from depth. More capability per unit of interface they learn. One implementation pays back across N call sites and M tests.
**Locality**: what maintainers get from depth. Change, bugs, knowledge, and verification concentrate in one place rather than spreading across callers. Fix once, fixed everywhere.
## Deep vs shallow
**Deep module** = small interface + lots of implementation:
```
┌─────────────────────┐
│ Small Interface │ ← Few methods, simple params
├─────────────────────┤
│ │
│ Deep Implementation│ ← Complex logic hidden
│ │
└─────────────────────┘
```
**Shallow module** = large interface + little implementation (avoid):
```
┌─────────────────────────────────┐
│ Large Interface │ ← Many methods, complex params
├─────────────────────────────────┤
│ Thin Implementation │ ← Just passes through
└─────────────────────────────────┘
```
When designing an interface, ask:
- Can I reduce the number of methods?
- Can I simplify the parameters?
- Can I hide more complexity inside?
## Principles
- **Depth is a property of the interface, not the implementation.** A deep module can be internally composed of small, mockable, swappable parts; they just aren't part of the interface. A module can have **internal seams** (private to its implementation, used by its own tests) as well as the **external seam** at its interface.
- **The deletion test.** Imagine deleting the module. If complexity vanishes, it was a pass-through. If complexity reappears across N callers, it was earning its keep.
- **The interface is the test surface.** Callers and tests cross the same seam. If you want to test *past* the interface, the module is probably the wrong shape.
- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a seam unless something actually varies across it.
## Designing for testability
Good interfaces make testing natural:
1. **Accept dependencies, don't create them.**
```typescript
// Testable
function processOrder(order, paymentGateway) {}
// Hard to test
function processOrder(order) {
const gateway = new StripeGateway();
}
```
2. **Return results, don't produce side effects.**
```typescript
// Testable
function calculateDiscount(cart): Discount {}
// Hard to test
function applyDiscount(cart): void {
cart.total -= discount;
}
```
3. **Small surface area.** Fewer methods = fewer tests needed. Fewer params = simpler test setup.
## Relationships
- A **Module** has exactly one **Interface** (the surface it presents to callers and tests).
- **Depth** is a property of a **Module**, measured against its **Interface**.
- A **Seam** is where a **Module**'s **Interface** lives.
- An **Adapter** sits at a **Seam** and satisfies the **Interface**.
- **Depth** produces **Leverage** for callers and **Locality** for maintainers.
## Rejected framings
- **Depth as ratio of implementation-lines to interface-lines** (Ousterhout): rewards padding the implementation. We use depth-as-leverage instead.
- **"Interface" as the TypeScript `interface` keyword or a class's public methods**: too narrow: interface here includes every fact a caller must know.
- **"Boundary"**: overloaded with DDD's bounded context. Say **seam** or **interface**.
## Going deeper
- **Deepening a cluster given its dependencies**, see [DEEPENING.md](DEEPENING.md): dependency categories, seam discipline, and replace-don't-layer testing.
- **Exploring alternative interfaces**, see [DESIGN-IT-TWICE.md](DESIGN-IT-TWICE.md): spin up parallel sub-agents to design the interface several radically different ways, then compare on depth, locality, and seam placement.
@@ -0,0 +1,47 @@
# ADR Format
ADRs live in `docs/adr/` and use sequential numbering: `0001-slug.md`, `0002-slug.md`, etc.
Create the `docs/adr/` directory lazily: only when the first ADR is needed.
## Template
```md
# {Short title of the decision}
{1-3 sentences: what's the context, what did we decide, and why.}
```
That's it. An ADR can be a single paragraph. The value is in recording *that* a decision was made and *why*, not in filling out sections.
## Optional sections
Only include these when they add genuine value. Most ADRs won't need them.
- **Status** frontmatter (`proposed | accepted | deprecated | superseded by ADR-NNNN`): useful when decisions are revisited
- **Considered Options**: only when the rejected alternatives are worth remembering
- **Consequences**: only when non-obvious downstream effects need to be called out
## Numbering
Scan `docs/adr/` for the highest existing number and increment by one.
## When to offer an ADR
All three of these must be true:
1. **Hard to reverse**: the cost of changing your mind later is meaningful
2. **Surprising without context**: a future reader will look at the code and wonder "why on earth did they do it this way?"
3. **The result of a real trade-off**: there were genuine alternatives and you picked one for specific reasons
If a decision is easy to reverse, skip it: you'll just reverse it. If it's not surprising, nobody will wonder why. If there was no real alternative, there's nothing to record beyond "we did the obvious thing."
### What qualifies
- **Architectural shape.** "We're using a monorepo." "The write model is event-sourced, the read model is projected into Postgres."
- **Integration patterns between contexts.** "Ordering and Billing communicate via domain events, not synchronous HTTP."
- **Technology choices that carry lock-in.** Database, message bus, auth provider, deployment target. Not every library: just the ones that would take a quarter to swap out.
- **Boundary and scope decisions.** "Customer data is owned by the Customer context; other contexts reference it by ID only." The explicit no-s are as valuable as the yes-s.
- **Deliberate deviations from the obvious path.** "We're using manual SQL instead of an ORM because X." Anything where a reasonable reader would assume the opposite. These stop the next engineer from "fixing" something that was deliberate.
- **Constraints not visible in the code.** "We can't use AWS because of compliance requirements." "Response times must be under 200ms because of the partner API contract."
- **Rejected alternatives when the rejection is non-obvious.** If you considered GraphQL and picked REST for subtle reasons, record it; otherwise someone will suggest GraphQL again in six months.
@@ -0,0 +1,60 @@
# GLOSSARY.md Format
## Structure
```md
# {Context Name}
{One or two sentence description of what this context is and why it exists.}
## Language
**Order**:
{A one or two sentence description of the term}
_Avoid_: Purchase, transaction
**Invoice**:
A request for payment sent to a customer after delivery.
_Avoid_: Bill, payment request
**Customer**:
A person or organization that places orders.
_Avoid_: Client, buyer, account
```
## Rules
- **Be opinionated.** When multiple words exist for the same concept, pick the best one and list the others under `_Avoid_`.
- **Keep definitions tight.** One or two sentences max. Define what it IS, not what it does.
- **Only include terms specific to this project's context.** General programming concepts (timeouts, error types, utility patterns) don't belong even if the project uses them extensively. Before adding a term, ask: is this a concept unique to this context, or a general programming concept? Only the former belongs.
- **Group terms under subheadings** when natural clusters emerge. If all terms belong to a single cohesive area, a flat list is fine.
## Single vs multi-context repos
**Single context (most repos):** One `GLOSSARY.md` at the repo root.
**Multiple contexts:** A `GLOSSARY-MAP.md` at the repo root lists the contexts, where they live, and how they relate to each other:
```md
# Glossary Map
## Contexts
- [Ordering](./src/ordering/GLOSSARY.md): receives and tracks customer orders
- [Billing](./src/billing/GLOSSARY.md): generates invoices and processes payments
- [Fulfillment](./src/fulfillment/GLOSSARY.md): manages warehouse picking and shipping
## Relationships
- **Ordering → Fulfillment**: Ordering emits `OrderPlaced` events; Fulfillment consumes them to start picking
- **Fulfillment → Billing**: Fulfillment emits `ShipmentDispatched` events; Billing consumes them to generate invoices
- **Ordering ↔ Billing**: Shared types for `CustomerId` and `Money`
```
The skill infers which structure applies:
- If `GLOSSARY-MAP.md` exists, read it to find contexts
- If only a root `GLOSSARY.md` exists, single context
- If neither exists, create a root `GLOSSARY.md` lazily when the first term is resolved
When multiple contexts exist, infer which one the current topic relates to. If unclear, ask.
+74
View File
@@ -0,0 +1,74 @@
---
name: domain-modeling
description: Build and sharpen a project's domain model. Use when discussing codebase terminology, writing or editing a GLOSSARY.md, or recording or editing an ADR.
---
# Domain Modeling
Actively build and sharpen the project's domain model as you design. This is the *active* discipline: challenging terms, inventing edge-case scenarios, and writing the glossary and decisions down the moment they crystallise. (Merely *reading* `GLOSSARY.md` for vocabulary is not this skill: that's a one-line habit any skill can do. This skill is for when you're changing the model, not just consuming it.)
## File structure
Most repos have a single context:
```
/
├── GLOSSARY.md
├── docs/
│ └── adr/
│ ├── 0001-event-sourced-orders.md
│ └── 0002-postgres-for-write-model.md
└── src/
```
If a `GLOSSARY-MAP.md` exists at the root, the repo has multiple contexts. The map points to where each one lives:
```
/
├── GLOSSARY-MAP.md
├── docs/
│ └── adr/ ← system-wide decisions
├── src/
│ ├── ordering/
│ │ ├── GLOSSARY.md
│ │ └── docs/adr/ ← context-specific decisions
│ └── billing/
│ ├── GLOSSARY.md
│ └── docs/adr/
```
Create files lazily: only when you have something to write. If no `GLOSSARY.md` exists, create one when the first term is resolved. If no `docs/adr/` exists, create it when the first ADR is needed.
## During the session
### Challenge against the glossary
When the user uses a term that conflicts with the existing language in `GLOSSARY.md`, call it out immediately. "Your glossary defines 'cancellation' as X, but you seem to mean Y. Which is it?"
### Sharpen fuzzy language
When the user uses vague or overloaded terms, propose a precise canonical term. "You're saying 'account': do you mean the Customer or the User? Those are different things."
### Discuss concrete scenarios
When domain relationships are being discussed, stress-test them with specific scenarios. Invent scenarios that probe edge cases and force the user to be precise about the boundaries between concepts.
### Cross-reference with code
When the user states how something works, check whether the code agrees. If you find a contradiction, surface it: "Your code cancels entire Orders, but you just said partial cancellation is possible. Which is right?"
### Update GLOSSARY.md inline
When a term is resolved, update `GLOSSARY.md` right there. Don't batch these up: capture them as they happen. Use the format in [GLOSSARY-FORMAT.md](./GLOSSARY-FORMAT.md).
`GLOSSARY.md` should be totally devoid of implementation details. Do not treat `GLOSSARY.md` as a spec, a scratch pad, or a repository for implementation decisions. It is a glossary and nothing else.
### Offer ADRs sparingly
Only offer to create an ADR when all three are true:
1. **Hard to reverse**: the cost of changing your mind later is meaningful
2. **Surprising without context**: a future reader will wonder "why did they do it this way?"
3. **The result of a real trade-off**: there were genuine alternatives and you picked one for specific reasons
If any of the three is missing, skip the ADR. Use the format in [ADR-FORMAT.md](./ADR-FORMAT.md).
+31
View File
@@ -0,0 +1,31 @@
---
name: grilling
description: Grill the user relentlessly about a plan, decision, or idea. Use when the user wants to stress-test their thinking, or uses any 'grill' trigger phrases.
disable-model-invocation: false
---
Interview the user relentlessly until you reach a shared understanding. Map this as a **design tree**: every decision branches into the decisions that hang off it.
Work the tree in **rounds**. The **frontier** is every decision whose prerequisites are already settled: the questions you can ask _now_ without guessing at answers you haven't heard yet. Ask the whole frontier in one round: number each question and give your recommended answer. Then wait for the user's answers before the next round.
Format a round like so:
```
❓ **Q1** - **<question title>**: <question body, might be multiple paragraphs, including multiple choices>
➡️ <your recommended answer>
---
❓ **Q2** - **<question title>**: <question body, might be multiple paragraphs, including multiple choices>
➡️ <your recommended answer>
```
Word each question so "yes" accepts your recommended answer.
Each round the user answers reshapes the tree: settled decisions push the frontier outward and unblock questions that depended on them. Recompute the frontier and ask the next round. A question whose answer depends on another question still open in this round belongs to a _later_ round, not this one.
Finding _facts_ is your job, never the user's. When a frontier question needs a fact from the environment (filesystem, tools, etc.), dispatch a sub-agent to find it; don't ask the user for anything you could look up yourself. Don't block on it: a running exploration is an unsettled prerequisite, so only the questions downstream of it wait for the sub-agent to report; ask the rest of the frontier now. The _decisions_ are the user's: put each to them and wait.
The session is done when the frontier is empty: every branch of the design tree visited, nothing left silently assumed. Do not act on it until the user confirms you have reached a shared understanding.
+100
View File
@@ -0,0 +1,100 @@
---
name: ponytail-audit
description: |
Quality audit of a whole repo: bugs, security holes, what breaks under real load, risky code without tests, slow paths, and what to delete, merge or split. Ranked, each finding explained in plain English. One-shot report, changes nothing. Use for "audit this codebase", "review the whole repo", "find bloat", "what can I delete", /ponytail-audit.
disable-model-invocation: false
---
Audit the whole repo like the senior developer who just inherited it and
will be paged when it breaks. Order of importance: correct, safe, holds under
load, tested, fast, lean. Lean still matters: every extra line must be read,
tested and fixed later. This is a report the user asked for, so give it in full.
## 1. Map first
- Audit what the user names: a folder, a package, or the whole repo.
Nothing named: the whole repo.
- Read the README, the deploy and build config, the dependency list, the
entry points (main, routes, handlers, jobs, CLI commands) and the tests.
- Find the expected load: one person running a script, or many users and
processes at once. Judge scale against that, and say which load you assumed.
- Trace the main flows end to end: where data comes in, what is stored,
what goes out. Read those paths fully: input from users, money, auth,
data writes, background jobs, anything shared between processes.
- Big repo: go deep where a mistake costs the most, not file by file. Say
which parts you did not read.
## 2. Look for
1. **Bug:** wrong result, crash, missed edge case (empty, zero, last item,
rounding, time zones), callers that disagree with what a function returns,
the same rule applied differently in two places.
2. **Risk:** security holes (injection, weak randomness, secrets in code,
missing checks on input from users), data loss (errors swallowed, writes
in the wrong order, no transaction).
3. **Scale:** fine for one user, wrong for many: check-then-write races, the
same work done by every process, memory or lists that only grow, a query
per item, O(n^2) on big input, per-process state that must be shared.
4. **Missing test:** risky logic (a branch, a parser, money, security, data
writes) with no test that fails when it breaks. One good test, not coverage.
5. **Speed:** big slowdowns are problems. Small wins (work repeated in a hot
loop) are suggestions; some software counts every millisecond.
6. **Lean:** code that should not exist or should be smaller.
- delete: dead code, unused options, flags and config, speculative features
- reuse: two helpers doing the same thing (keep one, name the path)
- stdlib / native: the standard library or platform already does it;
a dependency doing what a few lines or the platform can do
- yagni: interface with one implementation, factory with one product,
wrapper that only passes calls through
- merge: near-copies that must change together
- split: one function or class doing several unrelated jobs, so it is
hard to read or test. Split by job, never by line count, and never into
helpers that exist only to make a function shorter.
## 3. Check before you report
- Every finding needs a concrete case: "this input or situation leads to this
wrong result". No case, no finding.
- Before calling code unused, grep the whole tree for it, including tests,
fixtures, config, and string or dynamic references.
- A shortcut marked with a `shortcut:` (or older `ponytail:`) comment that names its limit is a
decision, not a finding, unless the expected load already crosses it.
- Propose the smallest fix that works. Prefer fixes that delete code. Never
add layers, frameworks or config the problem does not need.
- No style taste, no "consider", no vague worries.
## 4. Output
Very simple English: short sentences, everyday words. Explain a technical
term the first time you use it. The reader may never have seen this code.
Start with `What this repo does:` in two or three sentences, and the load
you assumed.
Then the findings in three groups, most important first, skip empty groups:
- **Must fix:** bug, security, data loss, breaks at the expected load.
- **Should fix:** risky code without a test, real slowness, duplication, a
function that mixes jobs, code that should not exist.
- **Nice to have:** small speed-ups, shorter forms.
Number findings across all groups, so the user can say "fix 2 and 5". At
most 20 findings; if you left smaller ones out, say how many.
Every finding has all four parts, each one or two short sentences:
2. **Orders land on the wrong day** (`billing/close_day.py:L40-52`)
- **What this is:** At midnight this job closes the day and bills all orders of that day.
- **Problem:** It takes "today" from the server clock, which runs in UTC. An order placed
at 00:30 in Berlin is billed on the day before.
- **Fix:** Compute the day once in the shop's time zone:
`datetime.now(ZoneInfo("Europe/Berlin")).date()`. One line, nothing else changes.
- **If we skip it:** Late orders show the wrong date, and accounting fixes them by hand.
End with:
- `Verdict:` one line: healthy, or what to fix first.
- `Lean: -<N> lines, -<M> dependencies possible.` when lean findings exist.
- `Not checked:` the parts you did not read or could not run.
Nothing found: `What this repo does:`, then `Healthy. Nothing to fix.` and
one line on what you checked.
One-shot report, changes no code.
+98
View File
@@ -0,0 +1,98 @@
---
name: ponytail-review
description: |
Quality review of a change: is the logic right, is it safe, does it hold under real load, is risky code tested, is it fast enough, and is every line needed. Reads the connected code, not only the diff. Each finding is explained in plain English. Use for "review this", "code review", "review the last commit", "review my PR", "is this over-engineered", /ponytail-review.
disable-model-invocation: false
---
Review a change like the senior developer who will be paged when it breaks.
Order of importance: correct, safe, holds under load, tested, fast, lean.
Lean still matters: every extra line must be read, tested and fixed later.
This is a report the user asked for, so give it in full.
## 1. Understand first
- Review what the user names: uncommitted or staged changes, a branch, a PR
link, or files. Nothing named: the uncommitted changes, or the last commit
if there are none.
- Read the diff, then the code it touches: callers of every changed function,
the functions it calls, the tests, the README.
- Trace the real flow: where data comes in, what is stored, what goes out.
- A change can break code it does not touch. When a signature, return value
or behavior changes, grep every caller.
- Find the expected load in the repo (README, deploy config): one person
running a script, or many users and processes at once. Judge scale against
that, and say which load you assumed.
## 2. Look for
1. **Bug:** wrong result, crash, missed edge case (empty, zero, last item,
rounding, time zones), a caller broken by the change, a fix applied in one
caller while the shared function stays broken.
2. **Risk:** security holes (injection, weak randomness, secrets, missing
checks on input from users), data loss (errors swallowed, writes in the
wrong order, no transaction).
3. **Scale:** fine for one user, wrong for many: check-then-write races, the
same work done by every process, memory or lists that only grow, a query
per item, O(n^2) on big input, per-process state that must be shared.
4. **Missing test:** risky new logic (a branch, a parser, money, security,
data writes, a bug fix) with no test that fails when it breaks. One good
test, not coverage.
5. **Speed:** big slowdowns are problems. Small wins (work repeated in a hot
loop) are suggestions; some software counts every millisecond.
6. **Lean:** code that should not exist or should be smaller.
- delete: dead code, unused options, speculative features
- reuse: the repo already has this helper (name the path)
- stdlib / native: the standard library or platform already does it; a
new dependency for a few lines
- yagni: abstraction with one implementation, config nobody sets
- merge: near-copies that must change together
- split: one function doing several unrelated jobs, so it is hard to read
or test. Split by job, never by line count, and never into helpers that
exist only to make a function shorter.
## 3. Check before you report
- Every finding needs a concrete case: "this input or situation leads to this
wrong result". No case, no finding.
- Re-read the lines and confirm: the caller exists, the value can really be
empty, the code really is unused.
- A shortcut marked with a `shortcut:` (or older `ponytail:`) comment that names its limit is a
decision, not a finding, unless the expected load already crosses it.
- Propose the smallest fix that works. Prefer fixes that delete code. Never
add layers, frameworks or config the problem does not need.
- No style taste, no "consider", no vague worries.
## 4. Output
Very simple English: short sentences, everyday words. Explain a technical
term the first time you use it. The reader may never have seen this code.
Start with `What this change does:` in two or three sentences.
Then the findings in three groups, skip empty groups:
- **Must fix:** bug, security, data loss, breaks at the expected load.
- **Should fix:** risky code without a test, real slowness, duplication, a
function that mixes jobs, code that should not exist.
- **Nice to have:** small speed-ups, shorter forms.
Number findings across all groups, so the user can say "fix 2 and 5".
Every finding has all four parts, each one or two short sentences:
2. **Orders land on the wrong day** (`billing/close_day.py:L40-52`)
- **What this is:** At midnight this job closes the day and bills all orders of that day.
- **Problem:** It takes "today" from the server clock, which runs in UTC. An order placed
at 00:30 in Berlin is billed on the day before.
- **Fix:** Compute the day once in the shop's time zone:
`datetime.now(ZoneInfo("Europe/Berlin")).date()`. One line, nothing else changes.
- **If we skip it:** Late orders show the wrong date, and accounting fixes them by hand.
End with:
- `Verdict: Ship.` or `Verdict: fix 1 and 3 first.`
- `Lean: -<N> lines possible.` when lean findings exist.
- `Not checked:` one line, if something mattered and you could not check it.
Nothing found: `What this change does:`, then `Looks good. Ship.` and one line
on what you checked.
Lists findings, changes no code.
+47
View File
@@ -0,0 +1,47 @@
---
name: ponytail
description: |
Lazy senior dev mode: the smallest change that fully solves the task, and a reply a busy human understands in one read. Use on any coding task (writing, fixing, refactoring, reviewing, choosing dependencies) and when the user says "ponytail", "be lazy", "simplest solution", "yagni", or complains about over-engineering or bloat. Levels: lite, full (default), ultra.
disable-model-invocation: false
---
# Ponytail
You are a lazy senior developer. The best code is the code never written. You solve the whole problem with the least new code. End your reply with one or two lines: what you skipped or did not check, and any risk the user must know.
Active for the whole session until the user says "stop ponytail" or "normal mode". Switch level: `/ponytail lite|full|ultra`.
## Before you write
Read the task and the code it touches. List every place your change must reach: callers, tests, fixtures, config, exports. Check what your change could break for users: data it would destroy or expose, callers that stop working. That is scope. Extra features are not.
## The smallest complete change
Take the first option that fully works:
1. Does it need to exist? Skip features, options and flexibility nobody asked for, and name them in one line. A vague request ("build me X") gets the smallest version that does the core job.
2. Already in this codebase (a helper, component, service, pattern)? Use it the way the surrounding code does.
3. Standard library or a platform feature? Use it, unless the project has its own. A house component beats a native widget.
4. An installed dependency? Use it. Never add a dependency for a few lines.
5. Can it be one line a reader gets at a glance? One line.
6. Otherwise: the minimum code that works.
- Be lazy about the solution, never about the change itself: finish every part the task needs, including the callers, tests and fixtures your change breaks.
- No abstraction, wrapper, type conversion, option, config, boilerplate or "for later" code nobody asked for. Keep values in the form the platform already gives you. Deletion beats addition. Keep the structure the codebase already has: its layers, interfaces and conventions.
- The shortest working diff wins, once you know everything it must touch. A one-liner that needs decoding is not short.
- Comment only the why the code cannot show, in one line.
- Bug fix: before you edit, grep every caller of the function you touch, then fix the root cause once in the shared code.
- Code you move or merge keeps its error handling and validation.
- Between options of equal size, take the one that is correct on edge cases.
- Lazy code without its check is unfinished: new non-trivial logic (a branch, a loop, a parser, money or security, or a whole new script or app) leaves one small test or an assert-based self-check. Trivial changes need none.
- A shortcut with a known limit gets a code comment in this form: `shortcut: <the limit>, <when to upgrade>`.
Never cut: validation at trust boundaries, error handling that prevents data loss, security, accessibility, the calibration real hardware needs, anything the user asked for.
## Levels
| Level | Behavior |
|-------|----------|
| **lite** | Build what was asked. Name the smaller option in one line and let the user pick. |
| **full** | The rules above. Default. |
| **ultra** | Also question the request: before building, push back on any part the need does not justify. |
+2
View File
@@ -0,0 +1,2 @@
profile.kdl
dms/
+22
View File
@@ -0,0 +1,22 @@
# Variables
config_dir := source_directory()
niri_dest := env("HOME") + "/.config/niri"
@default:
just --list
# Deploy Niri configuration with specified profile (dms or noctalia)
deploy profile="dms": (switch profile)
@echo "Deploying Niri configuration..."
mkdir -p ~/.config
ln -sfnT {{config_dir}} {{niri_dest}}
@echo "Deployment successful!"
# Switch active desktop profile (dms or noctalia)
switch profile:
ln -sf {{profile}}.kdl {{config_dir}}/profile.kdl
-niri msg action load-config-file
-pkill -x dms
-pkill -f "noctalia-shell"
-niri msg action spawn-sh -- "{{ if profile == "dms" { "dms run --session" } else { "qs -c noctalia-shell" } }}"
@echo "Switched Niri profile to {{profile}}"
+44
View File
@@ -0,0 +1,44 @@
# Niri Window Manager Configuration
Configuration files for the [Niri](https://github.com/YaLTeR/niri) scrollable-tiling Wayland compositor, with modular profiles for [DMS](https://github.com/AvengeMedia/dms) and [Noctalia](https://docs.noctalia.dev/).
## Installation
### Fedora / COPR
1. Enable the DMS COPR repository and install Niri + DMS:
```sh
sudo dnf copr enable avengemedia/dms
sudo dnf install niri dms
```
2. (Optional) Install Noctalia:
```sh
sudo dnf install noctalia
```
> **Note**: Both shells are managed directly by Niri (`spawn-at-startup`) through the active profile (`profile.kdl`), ensuring only the selected shell runs. Do not hook DMS to `niri.service` via `systemctl add-wants`.
## Deployment & Profiles
Deploy configuration (defaults to `dms` profile):
```sh
just niri::deploy
# or deploy directly with a specific profile:
just niri::deploy noctalia
```
Switch active desktop profile:
```sh
just niri::switch dms
just niri::switch noctalia
```
## Structure
- `config.kdl`: Main entry point (includes modular configs and `profile.kdl`).
- `dms.kdl`: DMS shell profile (starts `dms run --session` and binds DMS IPC hotkeys).
- `noctalia.kdl`: Noctalia shell profile (starts `qs -c noctalia-shell` and binds Noctalia IPC hotkeys).
- `dms/`: DMS-specific layouts, binds, colors, and rules.
- `screens/`: Monitor and display configurations.
- `keybindings.kdl`, `layout.kdl`, `rules.kdl`, `input.kdl`: Modular compositor settings.
+19
View File
@@ -0,0 +1,19 @@
include "misc.kdl"
include "screens/marvin.kdl"
include "screens/boobeul.kdl"
include "screens/home.kdl"
include "screens/hei.kdl"
include "screens/heifr.kdl"
include "screens/isc.kdl"
include "screens/lab320.kdl"
include "input.kdl"
include "layout.kdl"
include "keybindings.kdl"
include "rules.kdl"
include "profile.kdl"
recent-windows {
off
}
// include "/binds.kdl"
+29
View File
@@ -0,0 +1,29 @@
//---------------------------------
//- Profile for DMS desktop shell -
//---------------------------------
spawn-at-startup "dms" "run" "--session"
spawn-at-startup "bash" "-c" "wl-paste --watch cliphist store &"
binds {
// Mod+Space hotkey-overlay-title="Application Launcher" {
// spawn "dms" "ipc" "call" "spotlight" "toggle";
// }
Mod+Alt+V hotkey-overlay-title="Clipboard Manager" {
spawn "dms" "ipc" "call" "clipboard" "toggle";
}
Mod+Alt+s hotkey-overlay-title="Settings" {
spawn "dms" "ipc" "call" "settings" "toggle";
}
Mod+N hotkey-overlay-title="Notification Center" {
spawn "dms" "ipc" "call" "notifications" "toggle";
}
Super+Alt+L hotkey-overlay-title="Lock the Screen: lock" {
spawn-sh "dms ipc call lock lock";
}
}
+21
View File
@@ -0,0 +1,21 @@
input {
touchpad {
tap
// dwt
// dwtp
// drag false
// drag-lock
natural-scroll
}
keyboard {
xkb {
layout "ch"
variant "fr"
// options "compose:prsc"
}
}
// warp-mouse-to-focus
// focus-follows-mouse max-scroll-amount="0%"
}
+260
View File
@@ -0,0 +1,260 @@
binds {
// Keys consist of modifiers separated by + signs, followed by an XKB key name
// in the end. To find an XKB name for a particular key, you may use a program
// like wev.
//
// "Mod" is a special modifier equal to Super when running on a TTY, and to Alt
// when running as a winit window.
//
// Most actions that you can bind here can also be invoked programmatically with
// `niri msg action do-something`.
// Mod-Shift-/, which is usually the same as Mod-?,
// shows a list of important hotkeys.
Mod+Shift+7 { show-hotkey-overlay; }
// Suggested binds for running programs: terminal, app launcher, screen locker.
// Mod+T hotkey-overlay-title="Open a Terminal: alacritty" { spawn "alacritty"; }
Mod+T hotkey-overlay-title="Open Terminal" { spawn "gnome-terminal"; }
// Mod+T hotkey-overlay-title="Open Terminal" { spawn "ghostty"; }
// Super+Alt+L hotkey-overlay-title="Lock the Screen: swaylock" {
// spawn-sh "swaylock -i [[/home/remi/Nextcloud/Pictures/Pictures/Farden/202486.jpg]:] --scaling fill --ring-color bb00cc --key-hl-color 880033 --line-color 00000000 --inside-color 00000088 --separator-color 00000000 --indicator-idle-visible";
// }
// Example volume keys mappings for PipeWire & WirePlumber.
// The allow-when-locked=true property makes them work even when the session is locked.
// Using spawn-sh allows to pass multiple arguments together with the command.
XF86AudioRaiseVolume allow-when-locked=true { spawn-sh "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.1+"; }
XF86AudioLowerVolume allow-when-locked=true { spawn-sh "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.1-"; }
XF86AudioMute allow-when-locked=true { spawn-sh "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"; }
XF86AudioMicMute allow-when-locked=true { spawn-sh "wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"; }
// Example brightness key mappings for brightnessctl.
// You can use regular spawn with multiple arguments too (to avoid going through "sh"),
// but you need to manually put each argument in separate "" quotes.
XF86MonBrightnessUp allow-when-locked=true { spawn "brightnessctl" "--class=backlight" "set" "+10%"; }
XF86MonBrightnessDown allow-when-locked=true { spawn "brightnessctl" "--class=backlight" "set" "10%-"; }
// Open/close the Overview: a zoomed-out view of workspaces and windows.
// You can also move the mouse into the top-left hot corner,
// or do a four-finger swipe up on a touchpad.
Mod+O repeat=false { toggle-overview; }
Mod+Q repeat=false { close-window; }
Mod+Left { focus-column-left; }
Mod+Down { focus-window-down; }
Mod+Up { focus-window-up; }
Mod+Right { focus-column-right; }
Mod+H { focus-column-left; }
Mod+J { focus-window-down; }
Mod+K { focus-window-up; }
Mod+L { focus-column-right; }
Mod+Ctrl+Left { move-column-left; }
Mod+Ctrl+Down { move-window-down; }
Mod+Ctrl+Up { move-window-up; }
Mod+Ctrl+Right { move-column-right; }
Mod+Ctrl+H { move-column-left; }
Mod+Ctrl+J { move-window-down; }
Mod+Ctrl+K { move-window-up; }
Mod+Ctrl+L { move-column-right; }
// Alternative commands that move across workspaces when reaching
// the first or last window in a column.
// Mod+J { focus-window-or-workspace-down; }
// Mod+K { focus-window-or-workspace-up; }
// Mod+Ctrl+J { move-window-down-or-to-workspace-down; }
// Mod+Ctrl+K { move-window-up-or-to-workspace-up; }
Mod+Home { focus-column-first; }
Mod+End { focus-column-last; }
Mod+Ctrl+Home { move-column-to-first; }
Mod+Ctrl+End { move-column-to-last; }
Mod+Shift+Left { focus-monitor-left; }
Mod+Shift+Down { focus-monitor-down; }
Mod+Shift+Up { focus-monitor-up; }
Mod+Shift+Right { focus-monitor-right; }
Mod+Shift+H { focus-monitor-left; }
Mod+Shift+J { focus-monitor-down; }
Mod+Shift+K { focus-monitor-up; }
Mod+Shift+L { focus-monitor-right; }
Mod+Shift+Ctrl+Left { move-column-to-monitor-left; }
Mod+Shift+Ctrl+Down { move-column-to-monitor-down; }
Mod+Shift+Ctrl+Up { move-column-to-monitor-up; }
Mod+Shift+Ctrl+Right { move-column-to-monitor-right; }
Mod+Shift+Ctrl+H { move-column-to-monitor-left; }
Mod+Shift+Ctrl+J { move-column-to-monitor-down; }
Mod+Shift+Ctrl+K { move-column-to-monitor-up; }
Mod+Shift+Ctrl+L { move-column-to-monitor-right; }
// Alternatively, there are commands to move just a single window:
// Mod+Shift+Ctrl+Left { move-window-to-monitor-left; }
// ...
// And you can also move a whole workspace to another monitor:
// Mod+Shift+Ctrl+Left { move-workspace-to-monitor-left; }
Mod+Shift+Ctrl+Page_Up { move-workspace-to-monitor-up; }
Mod+Shift+Ctrl+Page_Down { move-workspace-to-monitor-down; }
Mod+Page_Down { focus-workspace-down; }
Mod+Page_Up { focus-workspace-up; }
Mod+U { focus-workspace-down; }
Mod+I { focus-workspace-up; }
Mod+Ctrl+Page_Down { move-column-to-workspace-down; }
Mod+Ctrl+Page_Up { move-column-to-workspace-up; }
Mod+Ctrl+U { move-column-to-workspace-down; }
Mod+Ctrl+I { move-column-to-workspace-up; }
// Alternatively, there are commands to move just a single window:
// Mod+Ctrl+Page_Down { move-window-to-workspace-down; }
// ...
Mod+Shift+Page_Down { move-workspace-down; }
Mod+Shift+Page_Up { move-workspace-up; }
Mod+Shift+U { move-workspace-down; }
Mod+Shift+I { move-workspace-up; }
// You can bind mouse wheel scroll ticks using the following syntax.
// These binds will change direction based on the natural-scroll setting.
//
// To avoid scrolling through workspaces really fast, you can use
// the cooldown-ms property. The bind will be rate-limited to this value.
// You can set a cooldown on any bind, but it's most useful for the wheel.
Mod+WheelScrollDown cooldown-ms=150 { focus-workspace-down; }
Mod+WheelScrollUp cooldown-ms=150 { focus-workspace-up; }
Mod+Ctrl+WheelScrollDown cooldown-ms=150 { move-column-to-workspace-down; }
Mod+Ctrl+WheelScrollUp cooldown-ms=150 { move-column-to-workspace-up; }
Mod+WheelScrollRight { focus-column-right; }
Mod+WheelScrollLeft { focus-column-left; }
Mod+Ctrl+WheelScrollRight { move-column-right; }
Mod+Ctrl+WheelScrollLeft { move-column-left; }
// Usually scrolling up and down with Shift in applications results in
// horizontal scrolling; these binds replicate that.
Mod+Shift+WheelScrollDown { focus-column-right; }
Mod+Shift+WheelScrollUp { focus-column-left; }
Mod+Ctrl+Shift+WheelScrollDown { move-column-right; }
Mod+Ctrl+Shift+WheelScrollUp { move-column-left; }
// Similarly, you can bind touchpad scroll "ticks".
// Touchpad scrolling is continuous, so for these binds it is split into
// discrete intervals.
// These binds are also affected by touchpad's natural-scroll, so these
// example binds are "inverted", since we have natural-scroll enabled for
// touchpads by default.
// Mod+TouchpadScrollDown { spawn-sh "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.02+"; }
// Mod+TouchpadScrollUp { spawn-sh "wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.02-"; }
// You can refer to workspaces by index. However, keep in mind that
// niri is a dynamic workspace system, so these commands are kind of
// "best effort". Trying to refer to a workspace index bigger than
// the current workspace count will instead refer to the bottommost
// (empty) workspace.
//
// For example, with 2 workspaces + 1 empty, indices 3, 4, 5 and so on
// will all refer to the 3rd workspace.
Mod+1 { focus-workspace 1; }
Mod+2 { focus-workspace 2; }
Mod+3 { focus-workspace 3; }
Mod+4 { focus-workspace 4; }
Mod+5 { focus-workspace 5; }
Mod+6 { focus-workspace 6; }
Mod+7 { focus-workspace 7; }
Mod+8 { focus-workspace 8; }
Mod+9 { focus-workspace 9; }
Mod+Ctrl+1 { move-column-to-workspace 1; }
Mod+Ctrl+2 { move-column-to-workspace 2; }
Mod+Ctrl+3 { move-column-to-workspace 3; }
Mod+Ctrl+4 { move-column-to-workspace 4; }
Mod+Ctrl+5 { move-column-to-workspace 5; }
Mod+Ctrl+6 { move-column-to-workspace 6; }
Mod+Ctrl+7 { move-column-to-workspace 7; }
Mod+Ctrl+8 { move-column-to-workspace 8; }
Mod+Ctrl+9 { move-column-to-workspace 9; }
// Alternatively, there are commands to move just a single window:
// Mod+Ctrl+1 { move-window-to-workspace 1; }
// Switches focus between the current and the previous workspace.
// Mod+Tab { focus-workspace-previous; }
// The following binds move the focused window in and out of a column.
// If the window is alone, they will consume it into the nearby column to the side.
// If the window is already in a column, they will expel it out.
Mod+ISO_Level3_Shift+egrave { consume-or-expel-window-left; }
Mod+ISO_Level3_Shift+dead_diaeresis { consume-or-expel-window-right; }
// Consume one window from the right to the bottom of the focused column.
Mod+Comma { consume-window-into-column; }
// Expel the bottom window from the focused column to the right.
Mod+Period { expel-window-from-column; }
Mod+R { switch-preset-column-width; }
// Cycling through the presets in reverse order is also possible.
// Mod+R { switch-preset-column-width-back; }
Mod+Shift+R { switch-preset-window-height; }
Mod+Ctrl+R { reset-window-height; }
Mod+F { maximize-column; }
Mod+Shift+F { fullscreen-window; }
// Expand the focused column to space not taken up by other fully visible columns.
// Makes the column "fill the rest of the space".
Mod+Ctrl+F { expand-column-to-available-width; }
Mod+C { center-column; }
// Center all fully visible columns on screen.
Mod+Ctrl+C { center-visible-columns; }
// Finer width adjustments.
// This command can also:
// * set width in pixels: "1000"
// * adjust width in pixels: "-5" or "+5"
// * set width as a percentage of screen width: "25%"
// * adjust width as a percentage of screen width: "-10%" or "+10%"
// Pixel sizes use logical, or scaled, pixels. I.e. on an output with scale 2.0,
// set-column-width "100" will make the column occupy 200 physical screen pixels.
Mod+Minus { set-column-width "-10%"; }
Mod+Equal { set-column-width "+10%"; }
// Finer height adjustments when in column with other windows.
Mod+Shift+Minus { set-window-height "-10%"; }
Mod+Shift+Equal { set-window-height "+10%"; }
// Move the focused window between the floating and the tiling layout.
Mod+V { toggle-window-floating; }
Mod+Shift+V { switch-focus-between-floating-and-tiling; }
// Toggle tabbed column display mode.
// Windows in this column will appear as vertical tabs,
// rather than stacked on top of each other.
Mod+W { toggle-column-tabbed-display; }
Print { screenshot; }
Ctrl+Print { screenshot-screen; }
Alt+Print { screenshot-window; }
// Application Launchers
// Mod+Space hotkey-overlay-title="Application Launcher" {
// spawn "ulauncher-toggle";
// }
// Mod+D hotkey-overlay-title="Run an Application: fuzzel" { spawn "fuzzel"; }
Mod+Space hotkey-overlay-title="Run dms spotlight" { spawn "dms" "ipc" "call" "spotlight" "toggle"; }
Mod+P hotkey-overlay-title="Set dynamic cast window" { set-dynamic-cast-window; }
Mod+Shift+P hotkey-overlay-title="Set dynamic cast monitor" { set-dynamic-cast-monitor; }
Mod+Alt+P hotkey-overlay-title="Clear dynamic cast target" { clear-dynamic-cast-target; }
Mod+Ctrl+P repeat=false hotkey-overlay-title="Mirror monitor" { spawn-sh "wl-mirror $(niri msg --json focused-output | jq -r .name)"; }
Mod+M hotkey-overlay-title="Start Telegram" { spawn "flatpak" "run" "org.telegram.desktop"; }
// XF86Launch5 { Ctrl+
}
+38
View File
@@ -0,0 +1,38 @@
layout {
gaps 2
// center-focused-column "always"
center-focused-column "on-overflow"
always-center-single-column
preset-column-widths {
proportion 0.5
proportion 0.66667
proportion 0.95
// fixed 2500
}
preset-window-heights {
proportion 0.33333
proportion 0.66667
proportion 1.0
}
default-column-width { proportion 1.0; }
focus-ring {
width 2
active-color "#4ABA4A" // 7fc8ff
inactive-color "#505050"
}
default-column-display "tabbed"
tab-indicator {
hide-when-single-tab
place-within-column
width 10
gaps-between-tabs 5
corner-radius 10
}
}
+18
View File
@@ -0,0 +1,18 @@
hotkey-overlay {
skip-at-startup
}
screenshot-path "~/Pictures/Screenshots/Screenshot from %Y-%m-%d %H-%M-%S.png"
window-rule {
// Rounded corners for a modern look.
geometry-corner-radius 20
// Clips window contents to the rounded corner boundaries.
clip-to-geometry true
}
debug {
// Allows notification actions and window activation from Noctalia.
honor-xdg-activation-with-invalid-serial
}
+24
View File
@@ -0,0 +1,24 @@
//--------------------------------------
//- Profile for Noctalia desktop shell -
//--------------------------------------
spawn-at-startup "qs" "-c" "noctalia-shell"
binds {
Mod+Alt+V hotkey-overlay-title="Clipboard Manager" {
spawn-sh "qs -c noctalia-shell ipc call launcher clipboard";
}
Mod+N hotkey-overlay-title="Notification Center" {
spawn-sh "qs -c noctalia-shell ipc call notifications toggleHistory";
}
Mod+Shift+N{
spawn-sh "qs -c noctalia-shell ipc call notifications toggleDND";
}
Super+Alt+L hotkey-overlay-title="Lock the Screen: lock" {
spawn-sh "qs -c noctalia-shell ipc call lockScreen lock";
}
}
+151
View File
@@ -0,0 +1,151 @@
window-rule {
match is-active=false
opacity 0.9
background-effect {
blur true
}
}
window-rule {
match app-id=r#"firefox$"#
match app-id=r#"zen$"#
// default-column-width { fixed 1920; }
default-window-height { proportion 1.0; }
}
window-rule {
match title="YouTube"
opacity 1.0
}
window-rule {
match app-id=r#"firefox$"# title="^Picture-in-Picture$"
match app-id=r#"zen$"# title="^Picture-in-Picture$"
open-floating true
default-column-width { proportion 0.5; }
default-column-display "tabbed"
opacity 1.0
}
// window-rule {
// match app-id="superProductivity"
// default-column-width { proportion 1.0; }
// default-window-height { proportion 0.33; }
// open-on-output "Dell Inc. DELL P2417H CW6Y78814R0B"
// }
window-rule {
match app-id="Plex"
open-on-output "BOE 0x0B7D Unknown"
default-column-width { proportion 1.0; }
opacity 1.0
}
window-rule {
match app-id="org.telegram.desktop"
default-column-width { fixed 1280; }
default-window-height { proportion 0.66; }
open-floating true
}
window-rule {
match app-id="org.gnome.Terminal"
match app-id="Alacritty"
default-column-width { fixed 1280; }
default-window-height { proportion 0.66; }
open-floating true
opacity 0.9
background-effect {
blur true
xray false
}
}
window-rule {
match is-window-cast-target=true
focus-ring { off; }
border {
active-color "#f38ba8"
inactive-color "#7d0d2d"
width 4
on
}
shadow { color "#7d0d2d70"; }
tab-indicator {
active-color "#f38ba8"
inactive-color "#7d0d2d"
}
}
window-rule {
match app-id=r#"^org\.keepassxc\.KeePassXC$"#
match app-id=r#"^org\.gnome\.World\.Secrets$"#
match app-id="org.telegram.desktop"
match app-id="superproductivity-bin"
match title="Microsoft Teams"
match title="Outlook"
match title="Bitwarden"
match title="Google Messages"
match title="Proton"
match app-id="org.mozilla.Thunderbird"
match app-id="org.mozilla.thunderbird_esr"
match app-id="net.thunderbird.Thunderbird"
match app-id="discord"
match app-id="com.slack.Slack"
match app-id="gcr-prompter"
block-out-from "screen-capture"
}
layer-rule {
match namespace="notification"
block-out-from "screen-capture"
}
window-rule {
match app-id=r#"^org\.gnome\."#
draw-border-with-background false
geometry-corner-radius 12
clip-to-geometry true
}
window-rule {
match app-id="Ulauncher"
open-floating true
focus-ring { off; }
}
window-rule {
geometry-corner-radius 12
clip-to-geometry true
}
window-rule {
match app-id="org.gnome.Nautilus"
match app-id="org.gnome.Evince"
match title="Settings"
// match app-id="app.zen_browser.zen"
match title="Star Citizen LUG Helper"
default-column-width { fixed 960; }
}
window-rule {
match app-id="explorer.exe"
open-fullscreen true
geometry-corner-radius 0
}
layer-rule {
match layer="top"
match layer="overlay"
background-effect {
xray false
}
}
+6
View File
@@ -0,0 +1,6 @@
output "LG Display 0x05EE Unknown" {
mode "1920x1080"
scale 1.5
transform "normal"
position x=0 y=0
}
+73
View File
@@ -0,0 +1,73 @@
output "Samsung Electric Company LS24A40xU H4TW301506" { // HEI-Samsung
// mode "1920x1080"
scale 1
transform "normal"
position x=-1920 y=-450
}
output "Dell Inc. DELL P2417H CW6Y779Q080B" { // HEI-center Dell
// mode "1920x1080"
scale 1
transform "normal"
position x=-1920 y=-450
}
output "Dell Inc. DELL P2417H CW6Y78814R0B" { // HEI-Dell
// mode "1920x1080"
scale 1
transform "90"
position x=-3000 y=-840
// position x=-3840 y=-450
layout {
always-center-single-column false
preset-column-widths {
proportion 1.0
}
preset-window-heights {
proportion 0.33333
proportion 0.66667
proportion 1.0
}
default-column-width { proportion 1.0; }
}
}
output "HP Inc. HP 534pm CNC51518S8" { // HEI-HP 21:9
// mode "1920x1080"
scale 1
// position x=1080 y=-1440
position x=-540 y=-1440
transform "normal"
layout {
center-focused-column "on-overflow"
preset-column-widths {
proportion 0.25
proportion 0.33333
proportion 0.5
// proportion 0.66667
}
preset-window-heights {
proportion 0.33333
proportion 0.66667
proportion 1.0
}
}
}
// output "Dell Inc. DELL P2417H CW6Y78814R0B" { // HEI-Dell
// // mode "1920x1080"
// scale 1
// position x=-3840 y=-450
// layout {
// center-focused-column "on-overflow"
// }
// }
// Kingston Tech Corporation 86 Monitor 0x00000001
output "Kramer Electronics Ltd. International VM-2HDT 295-883450100" { // Classroom 23N319
// mode "1920x1080"
scale 1
position x=-960 y=-1080
}
+7
View File
@@ -0,0 +1,7 @@
output "HP Inc. HP E24 G5 CN44151HCH" {
// mode "1920x1080"
scale 1
transform "normal"
position x=-1920 y=-350
}
+31
View File
@@ -0,0 +1,31 @@
output "Philips Consumer Electronics Company PHL 499P9 AU02027013590" { // Philips 32:9
mode "3840x1080"
scale 1
transform "normal"
position x=-360 y=-1080
layout {
center-focused-column "on-overflow"
preset-column-widths {
proportion 0.25
proportion 0.33333
proportion 0.5
// proportion 0.66667
}
preset-window-heights {
proportion 0.33333
proportion 0.66667
proportion 1.0
}
default-column-width { fixed 1900; }
}
}
output "Dell Inc. DELL 1707FP XP27769JBEZQ" { // Small Dell
mode "1280x1024"
scale 1
transform "180"
position x=1920 y=0
}
+75
View File
@@ -0,0 +1,75 @@
output "Dell Inc. DELL S3425DW HFWNR44" {
// mode "2520x1080"
scale 1
transform "normal"
position x=-3440 y=-900
layout {
center-focused-column "on-overflow"
preset-column-widths {
proportion 0.25
proportion 0.33333
proportion 0.5
proportion 0.75
proportion 0.66667
}
// preset-window-heights {
// proportion 0.33333
// proportion 0.66667
// proportion 1.0
// }
}
}
output "Dell Inc. DELL S3425DW 1DYNR44" {
// mode "2520x1080"
scale 1
position x=-3440 y=-540
// position x=-540 y=-1440
transform "normal"
layout {
center-focused-column "on-overflow"
preset-column-widths {
proportion 0.25
proportion 0.33333
proportion 0.5
proportion 0.66667
}
preset-window-heights {
proportion 0.33333
proportion 0.66667
proportion 1.0
}
}
}
output "Samsung Electric Company PC Monitor Unknown" {
scale 2
// position x=-3440 y=-540
transform "normal"
}
output "Dell Inc. DELL S3425DW 3FWNR44" {
// mode "2520x1080"
scale 1
transform "normal"
layout {
center-focused-column "on-overflow"
preset-column-widths {
proportion 0.25
proportion 0.33333
proportion 0.5
proportion 0.66667
}
preset-window-heights {
proportion 0.33333
proportion 0.66667
proportion 1.0
}
}
}
+48
View File
@@ -0,0 +1,48 @@
output "HP Inc. HP E24 G4 CN432306YR" { // HEI-Samsung
// mode "1920x1080"
scale 1
transform "normal"
position x=-1920 y=-450
}
output "HP Inc. HP E24 G4 CN43240DK9" {
// mode "1920x1080"
scale 1
transform "90"
position x=-3000 y=-840
// position x=-3840 y=-450
layout {
always-center-single-column false
preset-column-widths {
proportion 1.0
}
preset-window-heights {
proportion 0.33333
proportion 0.66667
proportion 1.0
}
default-column-width { proportion 1.0; }
}
}
output "Dell Inc. DELL P3425WE 1KV1Z54" { // Dell side teacher place
position x=-760 y=-1440 // Up
// position x=-3440 y=-720 // Side
layout {
always-center-single-column false
preset-column-widths {
proportion 0.33333
proportion 0.5
proportion 0.66667
proportion 0.99
}
default-column-width { proportion 0.66667; }
}
}
output "Dell Inc. DELL P2419H B9JSPF3" {
// mode "1920x1080"
scale 1
transform "normal"
position x=-1920 y=-450
}
+7
View File
@@ -0,0 +1,7 @@
output "BOE 0x0B7D Unknown" {
off
mode "1920x1080"
scale 1
transform "normal"
position x=0 y=0
}
+2 -3
View File
@@ -1,10 +1,9 @@
# Variables
dotfiles_dir := justfile_directory()
dotfiles_dir := source_directory()
plugin_dest := env("HOME") + "/.local/share/xxh-plugin-zsh-zz-my-zshrc"
xxh_config_dest := env("HOME") + "/.config/xxh/config.xxhc"
default:
@just --list
default: deploy
# Deploy and build xxh configuration
deploy: