🚧 Important:
Peace is a work in progress, and this website serves to communicate the project vision.
Approximately 20% of the features listed on this page are implemented; a substantial amount of the completed work has been foundational and exploration.
Peace is a framework to build robust, understandable software automation, incrementally.
The Peace Advantage
Visibility
> envman status Using profile development app: `web_app` out-of-date server: not exists upload: `web_app` not uploaded > envman diff app: `web_app` will be compiled server: will be launched upload: `web_app` will be uploaded
Automation is not just about performant execution, but understanding the state of things, and what automation would alter.
Understanding is not "how much information can be output", but "how information is best presented".
Peace presents the highest value information at a glance, with easy options to go deeper.
Adaptive Presentation
> envman ensure # interactive ✅ app ▰▰▰▰▰▰▰▰▰▰▰▰▰ built in 4s 🔨 server ▰▰▰▰▱▱▱▱▱▱▱▱▱ el: 7s, eta: 9s ⏳ upload ▱▱▱▱▱▱▱▱▱▱▱▱▱ deps: [server] * To stop, press Ctrl + C * For detail, in another terminal run: envman progress --detail
# ci
server | 1/5 | 0s | vm requested
app | 1/1 | 4s | built
server | 2/5 | 7s | os booted
server | 3/5 | 10s | pkgs installed
Peace presents information and actions adaptively:
- Progress presented as bars when used interactively, and single line logs in CI.
- JSON when returned as a web response.
- HTML elements when rendered in a browser -- WASM / web application.
Empirical Usability
> envman ensure ✅ app ▰▰▰▰▰▰▰▰▰▰▰▰▰ built in 4s ⚠️ server ▰▰▰▰▰▰▰▱▱▱▱▱▱ el: 33s, eta: 7s ⏳ upload ▱▱▱▱▱▱▱▱▱▱▱▱▱ deps: [server] * To stop, press Ctrl + C * For detail, in another terminal run: envman progress --detail ⚠️ warn: server may have stalled. Last message: (9s ago) Running `sudo apt install -y sysstate`
Peace automatically tracks execution metrics. This enables:
- Proactive Outlier Detection: Prompts based on outliers to historical averages.
- Highest Impact Optimization: Targeting efficiency improvements at the most frequent operations, or the slowest processes.
Understandable Errors
> envman ensure ✅ app ▰▰▰▰▰▰▰▰▰▰▰▰▰ built in 4s ❌ server ▰▰▰▰▰▰▰▱▱▱▱▱▱ el: 33s, eta: 7s 🚫 upload ▱▱▱▱▱▱▱▱▱▱▱▱▱ deps: [server] Error: server_package_install × Server packages failed to install. ╰─▶ Unable to locate package sysstate ╭─[server/config.yaml:1:1] 1 │ packages: 2 │ - sysstate · ───┬──── · ╰── defined here ╰──── Help: Ensure spellings are correct
Peace presents errors in the much loved Rust compiler error format, through compatibility with miette
by design.
- The source parameter(s) that cause the error are presented to the user, reducing work to find it.
- Suggestions on how to recover help the user move forward.
People don't feel lost when what they do doesn't work; they feel lost when they don't have a way to move forward.
Execution History
> envman log profile: development 2023-01-25+1300 (2 days ago) * ✅ 8 15:28:20 envman clean * ✅ 7 14:56:32 envman ensure * ✅ 6 14:48:22 envman ensure * ❌ 5 14:47:19 envman ensure * ✅ 4 14:31:48 envman ensure 2023-01-24+1300 (3 days ago) * ✅ 3 17:05:17 envman clean * ✅ 2 16:32:08 envman ensure * ✅ 1 16:29:59 envman ensure
> envman show last execution: 8 command: envman clean 2023-01-25T15:28:20+1300 (2 days ago) app: up-to-date to not-exists server: `abc-103abfe` to None upload: n/a
Peace stores execution summaries in its structured form, making it easy to review what was done, or analyzed with a different presentation.
Constrained Code
trait ItemSpec {
type State: /* .. */;
type StateDiff: /* .. */;
async fn state_current(&self, ..) -> _;
async fn apply_exec(&self, ..) -> _;
/* .. */
}
impl Presentable for ServerState {
fn present(&self, presenter: &Presenter) {
presenter
.name(self.server_name)
.desc(self.server_status)
}
}
Compile time constraints (with all features) means correctness, safety, and ease-of-use by design:
- For every item creation, there is a clean up.
- Every command has a target state, so multiple executions is not dangerous.
- Item states must be:
- Fetchable: For idempotence, this allows automation to skip to where it stopped.
- Presentable: In short for comprehension, in detail for informed decisions.
- Constraints enable Peace to provide common flows, and adapt information for each target.
⛓️ It is these constraints that give us freedom
Incremental Maturity
[dependencies.peace]
version = "0.0.?"
features = [
"error_reporting",
"output_colorized",
"output_json",
"output_progress",
"state_current", # 🚧
"state_goal", # 🚧
"state_diff", # 🚧
# ..
]
🐚 Instead of writing shell scripts, then transitioning to larger tools as complexity grows, existing logic is extended by enabling features in the Peace crate.
async fn apply_exec(
state_current: Self::State,
state_goal: Self::State,
+ state_diff: Self::StateDiff,
) -> Result<(), E>
🦀 Compilation errors show the code that needs updating, you don't have to work to find out.
Building Blocks / Concepts
Item Specification
A collection of functions to manage an item, e.g. application compilation, file upload, server existence.
Base functions:
- Current: Retrieve the current state.
- Goal: Retrieve the goal state.
- Diff: Diff the current and goal states.
- Ensure: Change the state from current to goal.
- Clean: Clean up the item.
- more to come
Item Specification Graph
A directed graph of Item Specs. Edges indicate forward execution order.
Functions can be executed in parallel when their predecessors' executions are complete.
Flows
A flow is a process that fulfills a business question or intent. Within a flow, the appropriate Item Specification function(s) are invoked for each item.
Examples:
- Discover and show the state of all items.
- Show what would change.
- Execute the automation.
Advanced flows may invert execution direction:
clean
cleans up items in reverse order.ensure
on a subset of items may forward alter some items, and clean others.
The Peace Disadvantage
Reasons you would not use Peace
-
Higher automation maturity levels implies higher cost of development:
Low maturity automation can evolve faster as it has fewer constraints. This is sustainable when:
- The number of users is not high.
- The cost of higher resilience and usability is not justified.
-
Rust is not as common a skillset as other languages, and requires substantial time to learn.
Inspirations
People
Through working with many people across different roles, it is apparent that a lot of issues when working with automation can be solved through clearer and more understandable communication – a dimension that deserves more attention in automation tooling.
Git
Git allows one to show the state of local and remote repositories, diff them, before committing and pushing the changes. Pushes are atomic and idempotent, meaning running the same command multiple times, whether or not the operation succeeded prior, has the same result.
The idea spawned from this is, instead of file content as the state, and patches being the diff, why not something – anything – user defined?
Rust
Rust's commitment to helping people learn, with clear explanations and examples, demonstrates that taking care of people is a priority that should not be left behind amidst technical advancement.