Best for
- Use when working with SWI-Prolog code.
Pyroxin/opinionated-claude-skills/opinionated-logic-development/skills/swi-prolog-programmer/SKILL.md
SWI-Prolog-specific tooling, standards, and idioms. Use when working with SWI-Prolog code. Emphasizes relational thinking, steadfastness, DCGs, constraints, and mandatory testing with PlUnit.
Decision brief
Expert-level SWI-Prolog development centers on thinking in relations not procedures, writing steadfast predicates that work in multiple directions, and embracing the declarative paradigm. The most critical mental shift: abandon "how" (procedural thinking) for "what" (declarative…
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/Pyroxin/opinionated-claude-skills --skill "opinionated-logic-development/skills/swi-prolog-programmer"Inspect the Agent Skill "swi-prolog-programmer" from https://github.com/Pyroxin/opinionated-claude-skills/blob/10c332aaec223fb10f63174029c4803f77eac269/opinionated-logic-development/skills/swi-prolog-programmer/SKILL.md at commit 10c332aaec223fb10f63174029c4803f77eac269. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
SWI-Prolog's design philosophy prioritizes knowledge-intensive interactive systems where logical correctness and development experience trump raw performance. As Jan Wielemaker (creator, 35+ years experience) explains: "My primary motivation has always been to build stuff that w…
make/0 is THE essential workflow tool. It checks timestamps, reloads only changed files, updates autoload indices, and preserves module context.
Target version: Latest development release (9.3.x series as of November 2025) Current stable: 9.2.9.1 (April 2025) Current development: 9.3.34 (November 2025)
When contributing to existing Prolog projects or open-source: - Respect existing coding style and conventions - Don't introduce modern features to projects targeting older versions - Follow the project's pack dependencies and version constraints - Propose improvements through pr…
Use SWI-Prolog when the problem involves: - Relational data querying (tabular and graph-shaped data) - Recursive structures (trees, nested data) - Search with backtracking - Constraint satisfaction problems - Symbolic manipulation and term rewriting - CPU-intensive server tasks…
Permission review
No configured static risk pattern was detected
This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.
Evidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 93/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 8 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Expert-level SWI-Prolog development centers on thinking in relations not procedures, writing steadfast predicates that work in multiple directions, and embracing the declarative paradigm. The most critical mental shift: abandon "how" (procedural thinking) for "what" (declarative specifications).
Related skills:
logic-programmer - Logic programming fundamentals (relations, unification, search)software-engineer - System design principles and architecturetest-driven-development - Testing philosophy (PlUnit section below covers SWI-specific practices)<logic_programming_fundamentals> Core logic programming principles:
p(X, Y) :- q(X), r(Y) as "X is related to Y when q(X) holds and r(Y) holds"
</logic_programming_fundamentals>This skill focuses on SWI-Prolog-specific tools, idioms, and practices that distinguish veteran developers from beginners.
Target version: Latest development release (9.3.x series as of November 2025) Current stable: 9.2.9.1 (April 2025) Current development: 9.3.34 (November 2025)
Aggressive adoption philosophy: Most developers should use development releases even for production. The development track is released every 2-4 weeks, typically robust, provides latest features, and issues are resolved quickly. The stable track (even minor versions) only receives critical patches and is intended for conservative deployments requiring predictable installations.
SWI-Prolog tries to minimize breaking changes and stay close to the ISO standard. From the SWI-Prolog documentation:1 "We try to make as few as possible changes that break backward compatibility..."
Version history reference: https://www.swi-prolog.org/ChangeLog
When contributing to existing Prolog projects or open-source:
The aggressive adoption philosophy applies ONLY to codebases you own.
<core_philosophy> SWI-Prolog's design philosophy prioritizes knowledge-intensive interactive systems where logical correctness and development experience trump raw performance. As Jan Wielemaker (creator, 35+ years experience) explains: "My primary motivation has always been to build stuff that works rather than stuff that allows writing an academic paper."
The critical insight: Backtracking provides a time machine for exploring computation paths. Any use of the dynamic database (assert/retract) breaks this superpower. The database is explicitly documented as "a non-logical extension to Prolog" that "destroys all these nice goodies" of logical search.
Veteran developers avoid assert/retract except when information must genuinely survive backtracking, which is rare. Instead: thread state through arguments. </core_philosophy>
Use SWI-Prolog when the problem involves:
Don't choose Prolog for:
The 2010 "Prolog Story" by Kyle Cordes documents a 90% cost reduction on a complex scheduling system—not from coding faster, but from thinking more clearly. The declarative approach forced better problem understanding.
The fundamental shift from imperative programming: think in terms of two variables instead of one. You cannot write i = i + 1 in Prolog because no value equals itself plus one. Instead: I #= I0 + 1 describes the relation between two different variables I0 and I.
As Markus Triska emphasizes: "The same variable cannot reflect two different states, old and new, at the same time."
Procedural reading (wrong): "To find X such that Y holds, do the following steps..."
Declarative reading (correct): "X is related to Y when the following conditions hold..."
For insert(Key, Tree, NewTree), read it as: "insert/3 shows how a key is related to a tree with and a tree without that key." The predicate describes a relationship, not a procedure.
Everything is a relation, so programs work in multiple directions. append/3 with one definition provides four methods:
?- append([1,2], [3,4], ZS). % List construction
ZS = [1,2,3,4].
?- append([1,2], YS, [1,2,3,4]). % List subtraction
YS = [3,4].
?- append(XS, YS, [1,2,3,4]). % Generate all partitions
XS = [], YS = [1,2,3,4] ;
XS = [1], YS = [2,3,4] ;
XS = [1,2], YS = [3,4] ;
XS = [1,2,3], YS = [4] ;
XS = [1,2,3,4], YS = [].
?- append(XS, YS, ZS). % Most general query
Four methods for the price of one! Write predicates that work bidirectionally when possible.
% If this succeeds:
?- foo(X), X = x.
% Then this must succeed:
?- foo(x).
% And vice versa - if foo(x) succeeds, then foo(X), X = x must succeed.
Predicates that fail this test are broken by definition. Test steadfastness by:
Example of non-steadfast code (broken):
% BAD: Only works when Max is unbound
get_max(X, Y, Max) :- X >= Y, Max = X.
get_max(X, Y, Max) :- X < Y, Max = Y.
?- get_max(3, 5, M). % Works
M = 5.
?- get_max(3, 5, 5). % Should succeed but fails!
false.
Steadfast version:
% GOOD: Works regardless of Max instantiation
max_value(X, Y, X) :- X >= Y.
max_value(X, Y, Y) :- X < Y, Y > X.
The official SWI-Prolog CLP(FD) documentation2 states: "If you are used to the complicated operational considerations that low-level arithmetic primitives necessitate, then moving to CLP(FD) constraints may, due to their power and convenience, at first feel to you excessive and almost like cheating. It isn't."
Constraints are integral to modern Prolog and designed to eliminate low-level primitives. When teaching Prolog, CLP(FD) constraints should be introduced before explaining low-level arithmetic because they're easier to explain and use.
The most important arithmetic constraint is #=/2, which subsumes both is/2 and =:=/2 over integers. Benefits:
% Not idiomatic (low-level, directional)
?- X is 5 + 3.
X = 8.
?- 8 is Y + 3. % Error! Can't work backwards
ERROR: is/2: Arguments are not sufficiently instantiated
% Idiomatic (declarative, multidirectional)
?- X #= 5 + 3.
X = 8.
?- 8 #= Y + 3. % Works backwards!
Y = 5.
?- Z #= A + B, Z #= 8, A #= 5. % Propagates constraints
Z = 8, A = 5, B = 3.
Standard approach for combinatorial problems:
solve(Vars) :-
Vars = [X, Y, Z],
Vars ins 1..10, % Domain declaration
X + Y #= Z, % Constraints
X #< Y,
label(Vars). % Search for solutions
Constraint propagation happens automatically. Use built-in constraints:
all_different/1 - All variables must take different valuessum/3 - Sum of list equals valuescalar_product/4 - Dot product constraintselement/3 - Indexing constraintscumulative/2 - Resource schedulingThis is the preferred approach for:
<dcg_patterns>
DCGs (Definite Clause Grammars) are not just for parsing—they're a general-purpose mechanism for threading state through computations. As Markus Triska states: "In every serious Prolog program, you will find many opportunities to use DCGs."
Veterans recognize DCGs as similar to monads in functional programming, providing automatic threading of two hidden arguments through all rules.
Use DCGs when:
The third case is critical for design—DCGs excel at implicit state threading when state flows through computation but only certain predicates need it.
Pattern recognition heuristic: When you see predicates passing through arguments like pred(..., N0, N1) where intermediate values N1, N2, N3 are only being threaded through without direct modification, consider DCGs. This is the accumulator pattern signaling a DCG opportunity.
The key idiom for explicit state access:
state(S), [S] --> [S]. % Read current state
state(S0, S), [S] --> [S0]. % Update state from S0 to S
Example: counting tree leaves without explicit threading:
num_leaves(Tree, N) :-
phrase(num_leaves_(Tree), [0], [N]).
num_leaves_(nil), [N] --> [N0], { N #= N0 + 1 }.
num_leaves_(node(_,Left,Right)) -->
num_leaves_(Left),
num_leaves_(Right).
Notice the second rule makes no reference to state—DCGs thread it implicitly. This is the power of the abstraction.
Tree to list conversion:
tree_nodes(nil) --> [].
tree_nodes(node(Name, Left, Right)) -->
tree_nodes(Left),
[Name],
tree_nodes(Right).
Pipeline pattern for transformations:
steps --> square, half, round.
square, [Y] --> [X], { Y is X * X }.
half, [Y] --> [X], { Y is X / 2 }.
round, [Y] --> [X], { Y is round(X) }.
convert(Float, Integer) :-
phrase(steps, [Float], [Integer]).
Lazy list processing with library(pio):
:- use_module(library(pio)).
process_file(Result) :-
phrase_from_file(my_dcg(Result), 'large_file.txt').
File contents loaded lazily; unused portions can be garbage collected.
From Paulo Moura (Logtalk creator): "DCGs provide a threading state abstraction: don't break it." Always use phrase/2 or phrase/3 to invoke DCGs. Never call DCG-compiled predicates directly—this breaks abstraction and ties code to implementation details.
</dcg_patterns>
<code_style>
The authoritative "Coding Guidelines for Prolog" (Covington et al., 2011, Theory and Practice of Logic Programming) states: "As far as we know, a coherent and reasonably complete set of coding guidelines for Prolog has never been published." This 39-page paper remains the definitive reference.
Reference: https://www.covingtoninnovations.com/mc/plcoding.pdf
Predicate names: Use underscore_style, never camelCase. Rationale: "Underscores resemble spaces...an important readability tool that is a thousand years old."
sorted_list/1, well_formed/1, in_tree/2)remove_duplicates/2, print_contents/1)Argument order: "Inputs before outputs" with the Space-Is-Time principle—if X is needed before Y temporally, place X before Y spatially. This aligns with first-argument indexing optimization.
Choose predicate names showing argument order: mother_child/2 not mother_of/2 (which is ambiguous).
Variable names: Use descriptive names like ResultsSoFar or Results_so_far. Single letters only with established conventions:
For threaded state: State0, State1, State2, ..., State (final) or State_in, State_tmp, State_tmp1, ..., State_out.
Indentation: 4 spaces (Covington) or 3 spaces (Lifeware/INRIA). Never tabs—"You cannot normally predict how tabs will be set." Maximum 80 columns.
Each subgoal on separate line except very short I/O sequences. First line has head and :- only:
predicate_name(Arg1, Arg2, Result) :-
goal1(Arg1, Intermediate),
goal2(Arg2, Intermediate, Result).
Vertical spacing:
Every public predicate must have PlDoc structured comments:
%! predicate_name(+Input:type, -Output:type) is det.
%
% Description using **Markdown** formatting.
% Multiple lines explaining behavior.
%
% @arg Input Description of input argument
% @arg Output Description of output argument
% @throws error_type When this condition occurs
%
% Example:
% ==
% ?- predicate_name(input, Output).
% Output = result.
% ==
predicate_name(Input, Output) :-
implementation.
Mode indicators (Covington system):
+ for nonvar input (must be instantiated)- for var output (will be instantiated)? for either direction@ for not further instantiated* for ground on entry! for mutable structureDeterminism indicators:
det - exactly once (deterministic)semidet - at most once (may fail, no choice points)multi - at least once (always succeeds, may have choice points)nondet - any number of times (may fail, may have choice points)
</code_style><cut_usage>
Green cut: Only prunes computation paths not contributing new solutions, doesn't change declarative meaning, safe to add or remove.
max(X, Y, X) :- X >= Y, !.
max(X, Y, Y) :- X < Y.
The cut is green because the test in the first clause guarantees the second won't succeed if the first does.
Red cut: Changes declarative meaning and program behavior.
% BAD: Red cut with major flaw
rc_minimum(X, Y, X) :- X =< Y, !.
rc_minimum(_, Y, Y).
?- rc_minimum(1, 2, 2). % Succeeds incorrectly!
true.
Guidelines:
make/0 is THE essential workflow tool. It checks timestamps, reloads only changed files, updates autoload indices, and preserves module context.
The edit-reload-test cycle:
?- edit(predicate). % Edit in configured editor
% [Make changes, save]
?- make. % Reload (auto-runs tests if configured)
?- test_predicate. % Manual testing
Configure tests to run automatically:
:- set_test_options([run(make)]).
Now every make. invocation runs the test suite.
Quote from documentation: "There is really no excuse not to write tests! Unit testing is less about testing than about proper and manageable coding—it's like having a lab notebook."
Tests document expected usage, validate implementation claims, and prevent regressions.
Basic test structure:
:- begin_tests(mymodule).
test(simple_case) :-
mymodule:predicate(input, expected).
test(with_verification, [true(X == 42)]) :-
mymodule:compute(X).
test(should_fail, [fail]) :-
mymodule:invalid_input(bad).
test(expecting_error, [error(type_error(_, _))]) :-
mymodule:predicate(wrong_type).
test(with_setup, [
setup(create_temp_file(File)),
cleanup(delete_file(File))
]) :-
mymodule:process_file(File).
test(all_solutions, [all(X == [1,2,3])]) :-
mymodule:generate(X).
test(nondet_expected, [nondet]) :-
mymodule:generate_multiple(_).
:- end_tests(mymodule).
Test organization:
.plt extension for test files matching .pl source filestest/ directoryswipl -g run_tests -t halt file.pl or ?- run_tests. from REPLLogic programming testing philosophy:
all(X == List))Tests document logical relationships more than execution order.
Run check. before every commit. This comprehensive check finds:
Individual checks:
list_undefined. - undefined predicateslist_void_declarations. - declared but not definedlist_trivial_fails. - always-failing predicatesGraphical cross-referencer: gxref. for visual dependency analysis.
Style checks (enable during development):
?- style_check(+singleton). % Warn on singleton variables
?- style_check(+discontiguous). % Warn on non-contiguous clauses
?- style_check(+no_effect). % Warn on ineffective code
Use gtrace, not trace: The graphical debugger is far superior to command-line.
?- gtrace. % Enable graphical tracing
?- gspy(pred/N). % Set spy point on predicate
Three-panel view shows source code, variables, and stack. Color-coded execution:
Supports hot-fixing (edit during debug), visualizes choice points, and provides source-level debugging.
Four-port model: Call → Exit (success) / Fail (failure) / Redo (backtrack)
Key commands: Space=step, s=skip, f=fail, r=retry, a=abort, b=break to REPL, e=edit source
Alternative: debug/3 library for instrumentation without tracing:
:- use_module(library(debug)).
?- debug(topic).
debug(algorithm, 'Processing: ~w', [Data]).
Zero overhead when disabled, fine-grained control by topic.
VSCode: Use "VSC-Prolog" or "New-VSC-Prolog" extensions. Features:
Emacs (recommended for serious development): Use Sweep (official, embeds SWI-Prolog as Emacs module).
Install from NonGNU ELPA:
(package-install 'sweeprolog)
Requires SWI-Prolog 8.5.18+ and Emacs 27+. Provides:
Alternative: lsp-mode + lsp_server pack for Language Server Protocol support.
<project_structure>
Standard directory structure for larger projects:
myproject/
├── load.pl # Main loader with environment setup
├── run.pl # Application starter
├── save.pl # Creates saved states
├── debug.pl # Debugging configuration
├── prolog/ # Source code
│ ├── main.pl
│ ├── module1.pl
│ └── myproject/ # Private/helper modules
│ └── internal.pl
├── test/ # Unit tests
│ ├── test_module1.plt
│ └── test_module2.plt
├── examples/ # Usage examples
├── pack.pl # Pack metadata if distributing
├── README.md
└── LICENSE
Key organizational files:
load.pl - Sets up environment (Prolog flags, file search paths) and loads sourcesrun.pl - Starts application by loading load.pl in silent mode and calling startup predicatessave.pl - Creates saved states with qsave_program/2debug.pl - Sets up debugging environmentEvery .pl file should be a module. Module name must match filename: my_module.pl contains :- module(my_module, [...]).
Export list includes only public predicates. Private modules go in subdirectories named after the pack.
:- module(module_name, [
exported_predicate/2,
another_export/1,
op(700, xfx, custom_op)
]).
%! exported_predicate(+Input, -Output) is det.
% Documentation using PlDoc syntax
exported_predicate(Input, Output) :-
helper_predicate(Input, Output).
% Private helper - not exported
helper_predicate(X, Y) :- Y is X * 2.
Set up project-specific file search paths:
:- prolog_load_context(directory, Dir),
asserta(user:file_search_path(myapp, Dir)).
user:file_search_path(graph, myapp(graph)).
user:file_search_path(ui, myapp(ui)).
:- use_module(graph(algorithms)).
:- use_module(ui(main_window)).
</project_structure>
<essential_libraries>
Mandatory (in order of importance):
member/2, append/3, length/2, reverse/2, nth0/3, sort/2, sum_list/2maplist/2-5, foldl/4-6, include/3, exclude/3, partition/4 (higher-order operations)whites//0, string//1, number//1, integer//1, digits//1 (DCG utilities)must_be/2, is_of_type/2, error constructors for proper error handlingHighly recommended:
#=/2, ins/2, label/1, all_different/1)aggregate/3-4, aggregate_all/3-4 for aggregation operationsoption/2-3, select_option/3-4, merge_options/3 for option list handlingdebug/3, assertion/1 for instrumentation[X,Y]>>Body) for inline goalsSpecialized but important:
<common_mistakes>
<from_imperative>
Trying to modify state destructively:
% WRONG: Trying to treat variables like imperative memory
X = 5,
X = X + 1. % ERROR: Can't unify 5 with 6!
% RIGHT: Use different variables for different states
X0 = 5,
X1 is X0 + 1. % Or: X1 #= X0 + 1
Using assert/retract for intermediate results:
% WRONG: Using database for computation state
compute(Input, Result) :-
retractall(temp(_)),
assert(temp(Input)),
process,
temp(Result).
% RIGHT: Thread state through arguments
compute(Input, Result) :-
process(Input, Result).
Over-reliance on execution order:
% WRONG: Assuming left-to-right evaluation matters for correctness
pred(X, Y) :-
compute_y(Y), % Assumes Y needed first
validate_x(X).
% RIGHT: Write predicates that work regardless of goal order
pred(X, Y) :-
validate_x(X),
compute_y(Y).
% Both orders should produce same logical result
Fighting with the language: Having a war with Prolog usually indicates procedural thinking hasn't been abandoned. Embrace relational thinking. </from_imperative>
<from_functional>
Expecting pattern matching to work one-way:
% Prolog uses unification (bidirectional), not pattern matching (one-way)
% This works in multiple directions:
?- append([1,2], [3,4], Xs). % Forward
?- append([1,2], Ys, [1,2,3,4]). % Backward
?- append(As, Bs, [1,2,3,4]). % Generate all splits
Missing that variables can be uninstantiated:
In Haskell, all variables are bound. In Prolog, variables can remain unbound and represent constraints:
?- X #> 5, X #< 10.
X in 6..9. % X is constrained but not bound to specific value
Trying to use guards that don't exist:
Prolog doesn't have guards like Haskell. Use goals in body instead:
% Not valid Prolog syntax (Haskell-style guards)
% max(X, Y, X) | X >= Y.
% Correct Prolog
max(X, Y, X) :- X >= Y.
max(X, Y, Y) :- X < Y, Y > X.
</from_functional>
<from_oop>
Creating unnecessary getter/setter predicates:
% WRONG: Java-style getters/setters
get_name(person(Name, _), Name).
set_name(person(_, Age), Name, person(Name, Age)).
% RIGHT: Direct unification
?- Person = person(Name, Age).
% Access fields by unification, not getters
Blindly using is_ prefix for everything:
From Covington: "Do not blindly import styles from other languages. For instance, do not blindly follow the Java tradition by calling everything in sight is_xxx or get_yyy."
Use appropriate Prolog naming:
sorted/1, member/2, connected/2is_sorted/1, is_member/2, is_connected/2Importing Java naming conventions:
% WRONG: camelCase (Java style)
myPredicate(inputValue, outputResult).
% RIGHT: underscore_style (Prolog convention)
my_predicate(input_value, output_result).
</from_oop> </common_mistakes>
<anti_patterns>
Red flags that code is written by someone fighting the language:
Using assert/retract for intermediate results: Breaks backtracking's time-machine debugging and is usually slow. Pass state through arguments instead.
Cut at end of last clause: pred(X) :- goal1, goal2, !. on the final clause—what alternatives is it eliminating? Almost always wrong.
Procedural variable reuse: Trying to write X = 5, X = 6 expecting X to "change." Use different variables: X = 5, Y = 6.
Directional code that only works one way: Not writing steadfast predicates. get_max(X, Y, Max) that fails if Max is already bound is broken.
Over-use of cuts and guards: Trying to write imperative control flow. Prolog is not C with weird syntax.
Using is/2 instead of #=/2 for integer arithmetic: Low-level arithmetic is directional, constraints are relational and propagate.
Not using higher-order predicates: Writing manual recursion instead of maplist/foldl. Veterans recognize standard patterns.
Poor error handling: No input validation, unclear error messages, not following ISO error conventions. Use must_be/2 from library(error).
Fighting relational nature: Thinking "how do I modify this" instead of "what relation holds between old and new state." </anti_patterns>
<design_patterns>
Accumulator pattern for aggregating results through recursion:
sum_list(List, Sum) :-
sum_list_(List, 0, Sum).
sum_list_([], Acc, Acc).
sum_list_([H|T], Acc0, Sum) :-
Acc1 is Acc0 + H,
sum_list_(T, Acc1, Sum).
Difference lists for O(1) list concatenation:
% Difference list append: O(1) instead of O(n)
append_dl(A-B, B-C, A-C).
% Example usage
?- append_dl([1,2|X]-X, [3,4|Y]-Y, List-[]).
List = [1,2,3,4].
Higher-order patterns with library(apply):
% Map operation
?- maplist(plus(1), [1,2,3], Result).
Result = [2,3,4].
% Filter operation
?- include(>(5), [1,6,3,8,2], Result).
Result = [6,8].
% Fold operation
?- foldl(plus, [1,2,3,4], 0, Sum).
Sum = 10.
Constraint programming pattern (covered earlier):
<production_checklist>
Before considering code production-ready:
Mandatory:
run_tests.check. runs without errors or warningsHighly Recommended:
show_coverage/1)examples/ directoryFor Distributed Packs:
pack.pl with complete metadataPrimary references:
Key papers:
Community resources:
Richard O'Keefe's three themes (The Craft of Prolog):
Jan Wielemaker on philosophy: "My primary motivation has always been to build stuff that works rather than stuff that allows writing an academic paper."
Markus Triska on declarative thinking: "Better ask: What are the cases and conditions that make this predicate true? Think in terms of relations between entities you are describing."
Kyle Cordes on the Prolog advantage: "We cut the cost/time of this implementation by 90% or more, not by coding more quickly, but by thinking more clearly."
From Covington et al. on efficiency: "The most efficient program is the one that does the right computation, not the one with the most tricks. By choosing a better basic algorithm, you can sometimes speed up a computation by a factor of a million."
On quality: "There is really no excuse not to write tests! Automatic testing of software during development is probably the most important Quality Assurance measure."
Jan Wielemaker. SWI-Prolog: Directions. https://www.swi-prolog.org/Directions.html ↩
Markus Triska. CLP(FD): Constraint Logic Programming over Finite Domains. SWI-Prolog. https://www.swi-prolog.org/pldoc/man?section=clpfd ↩
Frequently asked questions
Expert-level SWI-Prolog development centers on thinking in relations not procedures, writing steadfast predicates that work in multiple directions, and embracing the declarative paradigm. The most critical mental shift: abandon "how" (procedural thinking) for "what" (declarative…
The source record exposes this install command: npx skills add https://github.com/Pyroxin/opinionated-claude-skills --skill "opinionated-logic-development/skills/swi-prolog-programmer". Inspect the command and pinned source before running it.
Alternatives
testdouble/han
Builds a feature specification from scratch through a relentless, evidence-based interview that walks the design tree decision-by-decision, resolving dependencies as it goes. Use when the user wants to plan, design, scope, specify, or flesh out a new feature, capability, or system behavior before implementation. Produces a feature specification focused on system behaviors, not implementation detail. Does not refine or stress-test an existing plan — use iterative-plan-review. Does not document al
Jamie-BitFlight/claude_skills
Use when building Python 3.11+ CLI apps (Typer/Rich), writing pytest test suites, fixing ruff linting or ty/mypy type errors, configuring pyproject.toml, creating portable scripts, or reviewing Python code. Activates on all Python implementation tasks — routes to specialist agents for CLI architecture, test design, packaging, and code review. Authoritative reference for modern Python 3.11-3.14 patterns and TDD workflows.
mgiovani/cc-arsenal
Multi-agent review team: architecture, security, performance, testing, style, docs/UX, plus an adversary that cross-examines the other 6, for security-sensitive, architectural, or large PRs (15+ files) where a single-agent pass risks missing cross-cutting issues. Use for auth/payments/PII changes, schema/pattern changes, compliance sign-off, or when asked to 'get the review team on this' / 'multi-agent review' / 'thorough review before merge'. For a standard PR or a quick pre-merge check, use /r
th3vib3coder/vibe-science
Scientific research engine for hypothesis testing, literature gap analysis, experimental validation, and data-driven discovery. Enforces adversarial review (Reviewer 2), 32 quality gates, tree search over hypotheses, confounder harness for quantitative claims, and serendipity detection. TRIGGER when: user asks to analyze scientific data, test hypotheses, validate findings, search for research gaps, design experiments, or investigate results. DO NOT TRIGGER when: pure code review, documentation w