Introduction

This is the documentation for the Lince project. If you find any errors feel free to submit a PR.

The tool used to construct this is the mdbook crate, which is used by the official Rust book and many other technologies for their documentation. We can customize the color palette, search, print, etc. mdbook uses Markdown (.md) files, supports hot-reloading during development, and outputs static files into a specified directory, which is ignored by Git for deployment purposes.

If you don't have Cargo installed yet, you can install it with Rustup. It comes with Rust and its toolchain—how convenient!

To install, build, and serve the manual easily with just, try running:

just book

If that doesn't work, try building and running the manual manually.

To install the tool that builds the manual, run:

cargo install mdbook

If cargo isn’t in your PATH, add it to your shell configuration (~/.bashrc or ~/.zshrc) so you don’t have to type the full path every time (i.e., ~/.cargo/bin/{program}). Run this in your terminal:

#bash
echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> ~/.bashrc
echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> ~/.zshrc

With mdbook installed, enter the project folder and type:

mdbook serve

If you want to choose the port:

mdbook serve --port 9999

MdBook Documentation

Installation

You can run Lince as an executable, here are the releases. Pick the latest one for your machine and operating system. After the download, unzip it and run the binary:

./lince

If you preffer to compile the source code, the easiest way is to download the repo and run:

cargo run

If you don't have cargo installed, you can install it with with Rustup.

Have fun.

Summary

Lince is a tool for registry, interconnection and automation of Needs and Contributions with open scope.

The phrase above is the densest way to explain Lince. The current page serves as an overview, and the subsequent chapters cover it in much more detail. Let's start with the registry part:

Registry

Users will start their Lince application for the first time, and that will create a personal database

(for UNIX systems [Linux and macOS] it is located at '~/.config/lince/lince.db').

That database is a Sqlite file, that is reffered by the application as a DNA. That file can be altered to make the app behave differently.

The behavior can be of: setting personal/professional tasks, modeling personal items, scheduling computer actions, act out economic trades between parties, and many more, the sky, your imagination and computing power is the limit.

Any app behavior mentioned above can be boiled down to a Need, or a Contribution to a Need. The differentiator of the two is a Quantity. If such quantity is negative, that will be a Need.

Having -2 Apples means you need to go and get two apples to be neutral, to satiate your needs. The same applies to a habit, having a -1 Quantity in Exercise means you need to exercise.

The previous description is the basis of the whole app, everything revolves around it.

Automation

If there is predictability in your Needs, and a fixed frequency is enough to describe them, then a simple automation can be constructed.

One can set the automatic every day change of the 'Studying' habit's Quantity to -1. And with another feature, if that Quantity is -1 a Command is sent to the computer that closes all programs that are gaming related.

Another point of automation is the forementioned DNA. One aspect of constructing systems is that many great ideas often are lost with time, memory and the passing away of those contributors. Common patterns and knowledge about production and maintenance of commodities, economic trades, access to resources and ways of living is scattered.

These patterns could be saved into some form of database, that when fed into a program like Lince, will create Needs and Contributions, so users can have a headstart in any endeavor. From production according to a bill-of-materials to morning routines and parties organization, these activities create Needs for gathering resources and acting out tasks.

Contributions to Lince DNAs are like creating blueprints for others to get up and running. They might not be a perfect fit, but allow for great customization. Currently the way of centralizing DNAs is the Github Repository.

Interconnection

With great customizability and automation of people's DNAs, the next barrier is the connection of those individual apps, turning each machine into a p2p node, also called a Lince Cell. The same way you create triggers and rules for the quantites of your DNA, you can do the same for others.

If one Market has 200 apples and you need 5 you can create a Transfer Proposal. The Quantity of money diminishes on your side, and the Apple one increases. On the Market side, a manual price can be inputed and accepted when proposals come, or it can be adaptive. Donations of clothes and asking people close to you for a tool would be similar, just without the money part.

Organization

Disclaimers

All the repositories in the Lince ecosystem have the GNU GPLv3 license. Lince is a non-profit project and crowdfunding is the source of development compensation:

GitHub Sponsors | Patreon | Apoia.se

Lince tries to facilitate and automate the connection between people and resources, by transforming needs and contributions into data. The gains and losses related to the interaction, such as transportation, production and services themselves, remain the responsibility and risk of the parties involved.

Contributions

The workflow of contributing to the Lince ecosystem can be of simply making a Pull Request. But if one wants to have certainty of developing a wanted feature, the best way is to see the DNA of Lince programming tasks.

The online resource to communicate is the Discord.

The git repositories hosted currently in the lince-social GitHub Organization mean this:

  • lince: the app's code and this documentation.
  • dna: the databases for different Lince behaviors.
  • .github: general stuff, like photos, icons and information about GitHub sponsors.

Tech Stack

Backend:

  • Programming Language: Rust
  • Server: Axum
  • Database: Sqlite | Easiest to replicate the concept of DNA.
  • Database Driver: SQLx | Fun async, previously was Rusqlite but didn't prototype that well.

Frontend:

  • Web:
    • Base: HTML, CSS
    • Templating (Backend): Maud
    • Framework: HTMX + Datastar (transitioning into)
  • Bevy:
    • Don't know yet, still learning, probably will use WASM.

Dirty Architecture:

  • Application
    • Providers: simple CRUD operations.
    • Use_cases: anything complex, business ruly, that calls providers or manipulates data.
    • Schema: structure of data that comes in or goes out through the endpoints, or an alias for a data structure as a Type so it doesnt clutter the screen.
  • Domain:
    • Entities: the most accurate representation of the main drivers of the application. The source of truth of Lince's concepts.
    • Repositories: traits for defining the methods of the real Infrastructure repositories (database operations).
  • Infrastructure:
    • Http:
      • Routers: the paths and arguments of endpoints.
      • Handlers: the functions that are called by endpoints, that receive the query params, path variables, header, body if wanted. Responsible for calling providers, use_cases and/or returning presentation functions (frontend).
    • Database:
      • Management: database connection, migrations and schema.
      • Repositories: implementation of Domain traits for database operations like get, update...
    • Utils: functions for quality of life, like logging.
    • Cross_cutting: dependency injection for a collection of many methods in different layers. Mostly for single database connection initiation.
  • Presentation
    • Html: the templates made with maud, or sometimes just big strings. that are returned from functions. These HTML may contain HTMX and/or Datastar. The directories are divided rudimentary by concepts/entities like 'operation', 'table', 'pages'.
    • Bevy: not implemented yet, but mainly for a more featureful and immersive GUI.

Rust

Rust is a Procedural, Compiled, Borrow Checked (Memory Safe(r)), Statically Typed, Lower Level Than Go And Higher Level Than C programming language. It offers great concurrency, async (hard) and robust unwanted behavior elimination. Has a powerful standard library but shines greatly with crates (dependencies), using cargo, it's package management system.

There are many ways to write procedures like any language. Some more idiomatic than others, with one liners, syntax sugar and macros. This manual serves as a way of helping to write good Rust procedures, outside of executing Clippy's suggestions (more info below).

You install Rust preferably through Rustup, which comes with the whole toolchain (you are going to need it), including:

  • rustc: the Rust compiler.
  • cargo: the package manager and build tool.
  • rustfmt: formats Rust code according to style guidelines.
  • clippy: a linter that provides suggestions to improve your code (micro best practices).
  • rust-analyzer: a language server for IDE support and code navigation.

There are awesome things built with Rust, including:

Read the next session to create a project and force me to put it in the list.

Rust

Learning Resources:

  1. Rust Book: chapters 1-6 will give you a simple base if you just want to hack something together. Passing through the entire book, doing the examples and understanding them deeply, will set you up for great vibe coding.

  2. Rustlings: for when you are done with the book. You will complete exercises on a broad spectrum of the language's features.

  3. Rust for Rustaceans: for a deeper dive in the language, good practices and crate recomendations.

  4. This Week in Rust: a weekly newsletter about Rust projects, crates and language changes. Amazing for keeping up to date with the ecosystem.

  5. Youtube Channels: Jon Gjengset | No Boilerplate | The Rustagen | Tsoding |Code to the Moon | fasterthanlime | chris biscardi | Mike Code

  6. Podcast: Rustacean Station

  7. Discord, Matrix and many more online communities are very welcoming to newbies.

Explanation

Debugging

1. Ergonomics

To observe values during debugging, you can use:

#![allow(unused)]
fn main() {
println!("User: {}", user);
}

However, if a message alongside the value isn't necessary, it's easier to write:

#![allow(unused)]
fn main() {
dbg!(&user);
}

Example:

#[derive(Debug)]
struct User {
    name: String,
}

fn main() {
    let user = User {
        name: "Chose".to_string(),
    };

    dbg!(&user);
    println!("{user:?}");
    println!("User's name is: {}", user.name)
}

You can run the snippet, and it will show only the 'println!' lines, not the 'dbg!'. The real stdout output would be this:

 [src/main.rs:11:5] &user = User {
     name: "Chose",
 }
 User { name: "Chose" }
 User's name is: Chose

We can see that the dbg! macro outputs more information with less effort. Here's a great example: link.

There are some crates to help your CI:

Cargo Audit

Audit your dependencies for crates with security vulnerabilities reported to the RustSec Advisory Database.

# Install
cargo install cargo-audit --locked

# Run
cargo audit

Cargo Udeps

See your unused cargo dependencies:

# Install
cargo install cargo-udeps --locked

# Run
cargo +nightly udeps

Cargo Vet

[...] tool to help projects ensure that third-party Rust dependencies have been audited by a trusted entity.

# Install
cargo install cargo-vet --locked

# Initialize a standard Vet criteria, this can be changed
cargo vet init

# Run
cargo vet

Tables

This is where the real fun begins.

Record

record
id
quantity
head
body
location

Lince is centered on the 'record' table, but like, according to the creator... like... what does he know?


recordDATA TYPE
idINTEGER
quantityFLOAT
headTEXT
bodyTEXT
location3D POINT (still thinking)

'id's are automatically generated.

'quantity' represents the availability of the record, if negative it is a Necessity, if positive, a Contribution, zero makes it not mean much, sometimes.

'head' and 'body' are meant to be parts of a whole, where one can be used for a short summary and the other a description, or one has all the information and the other holds tags for filtering through views. With a pubsub protocol, one can send a short information of the record, in this case it can be the head, and put the rest in the body. Only those interested in the head will ask for the body of the record. That way the minimum amount of information is sent over the network, making it faster and stuff, I think.

'location' is an important information for interactions outside of computers (they exist, it's insane) or any other use you want to give it.


recordDATA TYPEUSER INPUT
idINTEGER
quantityFLOAT-1
headTEXTEat Apple
bodyTEXT
locationPOINT

So, for an example, imagine that you like apples and you want to create a task to eat it today.

You create a 'record', giving it '-1' to the 'quantity', for that action is a Necessity in your life right now, and 'Eat Apple' to the 'head'.


recordDATA TYPEUSER INPUTACTUAL RECORD
idINTEGER1
quantityFLOAT-1-1
headTEXTEat AppleEat Apple
bodyTEXTNULL
locationPOINTNULL

The end result, on the database, is this record.


Here is an example of different possible records for individual items and actions.

idquantityheadbodylocation
1-1Eat AppleNULLNULL
2-1AppleItem, FoodNULL
30Brush TeethAction, HygieneNULL
43ToothbrushItem, HygieneNULL
5-1MeditateActionNULL

Views

COLUMNSDATA TYPE
idINTEGER
nameTEXT
queryTEXT

Views are ways to select records.

A view will have a name, so it is human readable and a query to display different data.

The query is made with SQL allowing you to select what columns you want to see, filtered, ordered and much more, just the way you want it.

Examples:

Let's grab the record table shown before.

idquantityheadbodylocation
1-1Eat AppleNULLNULL
2-1AppleItem, FoodNULL
30Brush TeethAction, HygieneNULL
43ToothbrushItem, HygieneNULL
5-1MeditateActionNULL

A view of things you need to buy may look like this:

COLUMNVALUE
id1
nameBuy
querySELECT * FROM record WHERE LOWER(body) LIKE '%item%' AND quantity < 0

And in this case, will display only:

idquantityheadbodylocation
2-1AppleItem, FoodNULL

Since no other records with a body containing 'Item' (lower, upper, pascal case...) exist with a negative quantity.

Collection

COLUMNSDATA TYPE
idINTEGER
nameTEXT
quantityINTEGER

A Collection is the name of a list of Views. Only one Collection is active at a time, with quantity 1, the rest is 0.

Collection View

COLUMNSDATA TYPE
idINTEGER
quantityINTEGER
collection_idINTEGER
view_idINTEGER

A Collection View is an intermediate table for grouping Views into a Collection. The quantity is the order in which they appear and if positive they are shown, negative ones are not.

Configuration

configurationDATA TYPE
idINTEGER
quantityINTEGER
languageTEXT
timezoneTEXT
styleTEXT

The Configuration table alters some behavior of the Lince application. Language and Timezone are what they appear, and style is for setting what colorscheme is used.

Karma

karmaDATA TYPE
idINTEGER
quantityINTEGER
nameTEXT
condition_idINTEGER
operatorTEXT
consequence_idINTEGER

Karma is a condition checker and an action taker. A constructor of if/then, behavior, inside your DNA. It does it by replacing symbols in the Condition that point to data with it's actual values, then evaluating it as a mathematical equation and according to the Operator. If the operator is '=' it lets only non zero values take effect, if it is '=*' it doesnt have that constraint.

This is an introduction to Karma. The full description, plus examples, will take place a little further ahead. This process is called a Delivery and it is run every 60 seconds, and sometimes instantly for some special cases.

Karma Condition

COLUMN NAMEDATA TYPE
idINTEGER
quantityINTEGER
nameTEXT
conditionTEXT

A Karma Condition is something checked by replacing parts of the string (text) with real values. A record with id 1 has a quantity of 5. When we set a Karma Condition to be 'rq1' we are saying the value evaluated will be 5 (at that Delivery).

Karma Consequence

COLUMN NAMEDATA TYPE
idINTEGER
quantityINTEGER
nameTEXT
consequenceTEXT

The Karma Consequence works the same way as Condition but instead of getting values it is responsible for setting what is supposed to change. It can be the activation of a Shell/SQL command, the changing of the value of a Record and more in the future, like making transactions, changing Quantities of other tables like Configuration and Collection Views, or changing DNAs.

Frequency

frequencyDATA TYPE
idINTEGER
quantityINTEGER
day_weekINTEGER
monthsINTEGER
daysINTEGER
secondsINTEGER
next_dateSTRING
finish_dateSTRING
catch_up_sumINTEGER

The frequency table holds account of a fixed period for returning a value of 1 or more. If a frequency occurs every 1 day and 60 seconds it might start, for example at 2030-01-01 10:00:00. When that time comes, if this Frequency exists in a Karma Condition it will be checked and updated, setting next_date to 2030-01-02 10:01:00.

The catch_up_sum is a multiplier, if many days have passed since the last check like 4, instead of each minute it returns one, if catch up sum is 1 it will in the same Deliver jump the next_date until it has surpassed the current time returning the amount of times. Anything else will not do that.

In Karma, Frequencies are represented by the letter 'f'. So setting in a Condition '-1 * f1' means Karma Delivery will check the returned number for the specific Frequency with Id 1 and multiply that by '-1'.

Command

commandDATA TYPE
idINTEGER
quantityINTEGER
nameTEXT
commandTEXT

The Command is a Shell command you can run in a bash Shell.

Example:

idquantitycommand
1touch grass.el

It is referenced in Karma Condition and/or Consequence as the letter 'c', followed by the id number, so this example would be 'c1'.

Query

COLUMN NAMEDATA TYPE
idINTEGER
quantityINTEGER
queryTEXT

The Query is an SQL command you can run.

Example:

idquantityquery
1Robert'); DROP TABLE users; --

It is referenced in Karma Condition and/or Consequence as the characters 'sql', followed by the id number, so this example would be 'sql1'.

Sum

sumDATA TYPE
idINTEGER
quantityINTEGER
record_idINTEGER
interval_relativeBOOL
interval_lengthINTERVAL
sum_modeINTEGER
end_lagINTERVAL
end_dateTIMESTAMP

This table is responsible for returning a sum of change. Change of a record's quantity over time. You have the 'record_id' to know what record to look for. 'interval_length' is a period, can be 1 day, 8 months, etc. If 'interval_relative' is TRUE, will sum all the changes ending now, starting at the past based on the 'interval_length' (ex: 'interval_length' of 8 months and 'interval_relative' is TRUE will make it look at the past 8 months). If FALSE an 'end_date' will need to be supplied. so the past 8 months ending in a certain date. 'end_lag' will give a space between now and the end point of a relative interval. So if the 'interval_length' is 8 months and 'interval_relative' is TRUE, an 'end_lag' of 2 months will make the sum look at the 2 months back to 10 months back, starting 10 months ago, ending 2 months ago. 'sum_mode' tells Lince what to sum, if 0 it's a delta, essentially doing a quantity now - quantity earlier. If it's negative, it sums all negative changes, positive, idem.

Examples

So you now know the parts of Karma. It's time to put everything together. Lets take this example:

Record

idquantityheadbody
10Exercise

Frequency

idquantitydaysnext_date
112030-01-01 10:00:00

Condition

idquantitynamecondition
1Daily-1 * f1

Consequence

idquantitynameconsequence
1Exercise (Automatically set)rq1

Karma

idquantitynamecondition_idoperatorconsequence_id
1Daily Exercise (Automatically set)1=1

With this data, every Karma Delivery (60 seconds) will check the validity of each condition. Frequency with id 1 'f1' will return 0 in all minutes of the day safe for one time, where it will return 1. Since the operator of the Karma with id 1 is '=' the expression in it's Condition '-1 * f1' will almost always be '-1 * 0' and will not have a consequence.

In the Karma delivery that is past the next_date of Frequency, the next_date is updated and the Condition is '-1 * 1'. Since that is equal to '-1' the Consequence 'rq1' will change the quantity of Record with Id 1, turning it into '-1'.

We go from this:

idquantityheadbody
10Exercise

To this:

idquantityheadbody
1-1Exercise

One could make Conditions like '(rq1 - 1) * f1' and a Consequence of 'rq2' so the number would not be fixated at -1, but would decrease by one every day based on rq1. The expressions can become very complicated, but unless you are doing finance, joinning multiple sources of data into two or three records like monthly costs/gains and runaway you will do simple expressions.

Example: Command

With the command table

Let's say you have a command:

idquantitynamecommand
31Radaradatouch grass.el

This command with ID 3 can be referenced in a Karma Consequence with 'c3'.

Consequence

idquantitynameconsequence
2Radarada (Automatically set)c3

We can reuse the Frequency, and Condition, creating just a Consequence and Karma to automate the running of this command.

Frequency

idquantitydaysnext_date
112030-01-01 10:00:00

Condition

idquantitynamecondition
1Daily-1 * f1

Karma

idquantitynamecondition_idoperatorconsequence_id
1Daily Radarada (Automatically set)1=2

This will daily run the Command 'touch grass.el'.


Alternativelly, you can make it so the Command is part of the Condition.

echo $(find ~/books/technology -type f | wc -l)

This command will output a number, which we can use inside a Condition.

Command

idquantitynamecommand
4Tech Books Countecho $(find ~/books/technology -type f | wc -l)
5Open Current Tech Bookpdfreader ~/books/techology/current/*

Condition

idquantitynamecondition
3Read Tech Task-1 * f1 * c4

Consequence

idquantitynameconsequence
3Open Current Tech Bookc5

Karma

idquantitynamecondition_idoperatorconsequence_id
1Daily Radarada (Automatically set)3=3

That will automatically open the current technology book one is reading. If the automatic opening is not ideal one can set it so the Consequence is changing the quantity of a Record:

idquantityheadbody
1-1Read Tech Book

When typing 1 in operation the quantity of this Record will be zero. If you have a Condition that is 'rq1 == 0' that will be evaluated to '1' and can trigger the Consequence 'c5'. Though this method needs one Karma expression to run 'c5' if 'rq1 == 0' and another to make it so if 'rq1 == 0' Condition then 'rq1' Consequence, making 'rq1' be '1' and not triggering the infinite opening of the Tech Book.

Transfer

This is from the old Postgres Schema and idea of Transfer, it is kept here whilst it is in TODO.

Table: transfer

transferDATA TYPE
idINTEGER
records_receivedJSON
records_contributedJSON
agreementJSON
agreement_timeTIMESTAMP
transfer_confirmationJSON
transfer_timeTIMESTAMP

WORK IN PROGRESS 'records_received' is a collection of records and their quantities that will interact with our records, things you will receive. 'records_contributed' are the records you will contribute and their quantities, to the records of other parties, can be more than one party. So you can receive 5 moneys and an apple for driving someone from A to B. You don't work with it, but you have a car and their destination was on the way of yours. 'agreement' is a collection of agreement by all parties involved. 'agreement_time' is the moment every party agreed for the conditions of the trade, who will receive what. 'transfer_confirmation' is also a collection but with a confirmation from all parties that the transfer was successful, and 'transfer_time' for saving the event's moment.

Dna

In practice, a different database. In essence, a different Lince behavior. Be it by swapping databases the app is pointing to or aggregating data from multiple databases it is the data the program has to run it's functionalities.

TODO.

History

This is from the old Postgres Schema and idea of History, it is kept here whilst it is in TODO.

historyDATA TYPE
idINTEGER
record_idINTEGER
change_timeSTRING
old_quantityFLOAT
new_quantityFLOAT

History is a table that automatically logs the change of a record's quantity, to use the 'sum' table.

Operations

You can type operations to perform actions anywhere in Lince. An input bar will show up, allowing for combinations of commands.

If you type '4c' a modal for creating a Record will pop up. Typing 'a' with a number, like 'a2' will make Configuration with id 2 be active, and others inactive, an easy way to change colorscheme. One handy one is 's' with a number, 's1' to run a command.

Just typing a number, like '23' will make the Record with id 23 have it's quantity become zero.

[#] Name[Key] Action
[0] Configuration[c] Create
[1] Collection[q] SQL Query
[2] View[k] Karma
[3] collection_View[s] Shell Command
[4] Record[a] Activate Configuration
[5] Karma_Condition
[6] Karma_Consequence
[7] Karma
[8] Command
[9] Frequency
[10] Sum
[11] History
[12] DNA
[13] Transfer

Modules

Inspired by the Emacs philosophy of being very complete with packages and modes, Lince is an app that tries to do everything. But everything is a lot. So to help specialize and minimize compile times and complexity a system of modules/plugins needs to exist.

The current state of things is to put everything inside the binary, because I am a noob. Next are some features that should probably be modules/plugins but are just there.

Mosca

M.O.S.C.A: Management of Operating Systems, Configuring Automatically. A great acronym, not just because I like to give animal names to my creations.

Mosca is to be the Rust code that will execute highly specific operations, running away from the philosophy of the core of Lince, which is generic. An example is Anicca, which mimics NixOS's awesome Impermanence: factory reset of system, safe for some specified directories and files.

Anicca

Warning

This is a foul piece of software, dangerous and destructive on unmastered hands.

Install

Download the repo, then run:

# Sudo means to run in Super User DO mode, where you have 'admin' capabilities,
# so the program can make actions that require elevated privileges.
# This is necessary for manipulating files that the system 'relies on' like '.cache';
# which in my machine is harmless to delete but without the 'sudo -E...' doesn't work.
sudo -E cargo run

Or download the latest Release's binary and then run:

./os

Configuration

The path to the configuration file is in your config dir + lince/os.toml

In Linux (Arch (with Archinstall) btw), the only system I tested it, the path would be ~/.config/lince/os.toml.

Anicca means 'impermanence' in Pali, Nicca means the contrary: permanence. A fitting name for the specification of what persists. The Anicca feature deletes all files and directories that are in the same dir as a specified file or directory. Nicca specifies files and dirs that should be ignored from that clean slate wipe.

This was robbed from NixOS's Impermanence flake, the only reason I stayed in NixOS for so long. I wanted that feature in every distro and built this.

If I where to summarize to the atomic level what this feature does when it reads your dotfile at os.toml it would be this:

One dir up that line is put into a 'list' of dirs that will have everything in it removed, except the dir specified.

(What?)

Let's look into some examples.

Let's say that the name of my user is 'myname', in this case the Home Directory would be '/home/myname', lets check out our mock dirs:

/home/myname/.config/lince
/home/myname/.config/helix
/home/myname/.config/nvim
/home/myname/.cache
/home/myname/Downloads

If LinceOS's config file's contents are:

[nicca]
list = [
 "/home/myname/.config"
]

Every dir inside 'home/myname', except for .config, it's subdirectories and files will be deleted. The remaining ones will be these:

/home/myname/.config/lince
/home/myname/.config/helix
/home/myname/.config/nvim

Great! Now let's say that LinceOS's config is this:

[nicca]
list = [
 "/home/myname/.config/lince",
 "/home/myname/.config/helix",
 "/home/myname/Downloads"
]

The remaining dirs and files will be these:

/home/myname/.config/lince
/home/myname/.config/helix
/home/myname/Downloads

The deleted ones:

/home/myname/.config/nvim
/home/myname/.cache

When we add one level of 'immersion' inside subdirs we make every 'sibling' subdir also elegible for removing. In the first example with just 'home/myname/.config' the '.config/nvim' dir wasn't specified, therefore it wasn't deleted, all in .config where spared.

But in the second case when specific subdirs in '.config' like 'helix', the program thought that dirs (and files) inside .config (except for the specified ones: 'lince' and 'helix') should be deleted. This removed nvim because this hypothetic user knows that it is objectivelly worse than helix.

Since we didn't specify anything in the root ('/') dir, LinceOS will not touch it, it only goes one dir up on each line in the config file, so if some user specifies in it's config file:

[nicca]
list = [
 "/home"
]

Every other dir in '/' will be deleted, that's bad in most cases, if you don't know if it's bad for you, it's bad for you.

Kamalie

Kamalie - The lie of desire.

Be able to use Lince's tables as the data to run the game, a different dna can be inputted, which is the dna of the game, using record with a quantity, body for darmas, i dunno. There could be a mode that wasnt classic kamalie, but entered a kamalie state/world with normal day to day lince data, being able to see the voxel world with normal data. that doesnt interact the same way classic kamalie does, being able to see in a different visual the application of a karma to a record with a frequency, if it will balloon in size.

Good Practices

Karma

Until Lince has Deterministic Simulation Testing (DST), you have to be mindfull of the Command table you produce, every command you set may possibly break your system if you don't tidy things up. If you have logic of running a command every hour if one record has quantity > X and you forget about it, any simple change will trigger it, so put guardrails for running things, be it Commands, Queries or even changing Record Quantities. Changes might cascade and deliver unforeseen consequences.

With DST this is easier to do, the plan is to have a containerized environment that runs a simulation of your system, isolated from the outside world. Your DNA (your personal configuration of lince) is a seed that can be run multiple times arriving at the same result (hopefully). Being able to run it with a high speed, changing the date (affecting the Frequency table) and record quantities will bring reproducible results. When you want to add something to your DNA you can check it's effects with a simulation and get info if it breaks anything in an edge case.

Command

Lince works with Sqlite files for it's database. It is recomended to frequently backup your DNAs, weekly, daily or hourly if you are paranoid. If some error or mistake happens, your information is safe.

Author's Style

Personal Note & Tips:

Modeling all items and actions to perform takes a while. Making a Lince DNA, understanding the possibilities is to me a long term effort, ever increasing the value you get from computers. The possibilites are vast, limited by one's domain of computers and imagination, when combined, wizardry skills arise.

From a usage standpoint, I recommend having several views, one for each table and a personal view for tasks, mine is:

SELECT * FROM record WHERE quantity < 0 AND (LOWER(body) LIKE '%task%' OR LOWER(body) LIKE '%item%') ORDER BY quantity ASC, body ASC, head ASC

I also use the 'body' column in 'record' table as a tag holder. So Record's bodies with Items and Tasks that have negative quantities appear in my 'Negatives' view, it is the one I most use.