diff --git a/ABOUT.md b/ABOUT.md
new file mode 100644
index 0000000..9c86ebc
--- /dev/null
+++ b/ABOUT.md
@@ -0,0 +1,117 @@
+# Opinionated Origins: Why Figtree Is Named the Way It Is
+
+## Words Matter
+
+Every package makes a choice about what to name things. Most developers treat
+naming as cosmetic — a label on a box. Figtree treats naming as architectural.
+The words you use to describe a system shape the system itself. They shape what
+you build next, what feels natural to extend, and what feels like it doesn't
+belong.
+
+Viper chose a snake. Cobra. Viper. The fangs-first family of Go configuration
+tooling. A snake is flat. It has no branches. It moves in one direction. It
+strikes. If you've ever been bitten by a race condition in a viper-backed
+application under concurrent load, the metaphor lands harder than intended.
+
+Figtree chose a tree. Specifically, the fig tree — one of the oldest cultivated
+plants in human history, appearing in more foundational texts than almost any
+other living thing. Not because of religion. Because of what a fig tree actually
+does.
+
+## What a Fig Tree Does
+
+A fig tree grows from a seed. It puts down roots that draw from the environment.
+It branches. Its branches bear fruit. The fruit contains the value. You harvest
+the fruit. You don't harvest the tree.
+
+That's the entire figtree API described in one paragraph.
+
+- `figtree.New()` or `figtree.Grow()` — plant the seed
+- `figs.NewString()`, `figs.NewInt()` — register properties, grow the branches
+- `figs.Parse()` or `figs.Load()` — draw from the environment
+- `*figs.String()`, `*figs.Int()` — harvest the fruit
+- `figs.Fig(key)` — access the fruit itself, not just its value
+- `figs.Mutations()` — observe how the fruit changes over time
+- `figs.Withered` — the original state before the environment changed it
+- `figs.Resurrect()` — regrow from dormant roots
+- `figs.Curse()` / `figs.Recall()` — dormancy and renewal
+- `figs.Pollinate()` — external forces updating the living tree
+- `figs.Branch()` — the tree literally branches, each branch its own tree
+
+None of these words were chosen arbitrarily. Each one maps to a real biological
+process that has a direct analog in what the code does. When a word fits its
+behavior this precisely, the API becomes memorable. You don't have to look up
+what `Resurrect` does. You already know.
+
+## Why the Naming Convention Enables Functionality Viper Lacks
+
+This isn't just aesthetics. The tree metaphor opened design space that a flat
+snake metaphor closes off.
+
+A snake is flat. Viper's configuration is a flat map with dot-notation keys
+pretending to be hierarchy. `viper.Get("db.host")` isn't a branch — it's a
+string with a period in it. The hierarchy is a convention, not a structure. You
+can't put rules on `db`. You can't put validators on `db`. You can't watch
+`db` change independently. You can't scope callbacks to `db`. Because `db`
+doesn't exist. Only `"db.host"` exists, as a string key in a flat map.
+
+A tree branches. `figs.NewBranch("db")` returns a real figtree. That branch
+has its own validators, its own callbacks, its own rules, its own aliases. It
+funnels mutations back to the root channel with the path recorded. It can be
+passed around, composed, and reasoned about independently. `db` exists because
+a tree has branches and a snake does not.
+
+The naming convention didn't just describe the API. It generated the API. Once
+you commit to the metaphor honestly, the next feature becomes obvious. Trees
+have branches. Branches bear fruit. Fruit can be withered or fresh. The tree
+can be cursed or recalled. Pollination brings external changes in. The language
+tells you what to build next.
+
+## The Concurrent Application Problem
+
+Figtree has been backing highly concurrent Go applications in enterprise
+environments for over six years — first as `configurable`, then as `figs`, now
+as `figtree`. Not because viper was unavailable. Because viper's known race
+conditions were unacceptable in production systems that couldn't afford to lock
+an external mutex around every configuration read.
+
+A tree is alive. It doesn't stop growing because something is reading its fruit.
+The concurrency model in figtree — `sync.RWMutex` used correctly throughout,
+read operations using `RLock` not `Lock`, `Store()` releasing locks before
+channel sends to prevent deadlock — these decisions came from six years of
+running configuration management under real concurrent load. The metaphor of a
+living tree that continues to operate while being observed isn't decorative.
+It's the design requirement.
+
+## On Adoption
+
+Figtree was built by someone who was adopted. Viper was not something to be
+adopted. The irony is precise and intentional.
+
+The packages you choose for your applications are not neutral. They carry the
+assumptions of their authors. A package named after a predator assumes adversarial
+relationships — between the config and the application, between defaults and
+overrides, between what you asked for and what you got. A package named after a
+living, branching, fruit-bearing tree assumes that configuration should grow
+with your application, bear real value, and be observable as it changes.
+
+The words you use manifest. Choose them carefully.
+
+## On Yeshua
+
+Figtree isn't a religious package. It doesn't require belief in anything except
+that good software is worth building carefully and naming honestly.
+
+But the fig tree appears in contexts most developers will recognize at some level
+whether they identify as religious or not. It represents discernment — the
+ability to look at something and know whether it bears fruit or doesn't. That
+instinct is what every engineer uses when evaluating a dependency.
+
+Does this bear fruit? Does it do what it says? Is it alive or is it dead wood?
+
+Figtree bears fruit. That's the whole argument.
+
+---
+
+*Figtree is maintained by [@andreimerlescu](https://github.com/andreimerlescu).*
+*License: MIT*
diff --git a/COMPARISON.md b/COMPARISON.md
new file mode 100644
index 0000000..910726b
--- /dev/null
+++ b/COMPARISON.md
@@ -0,0 +1,383 @@
+# Figtree vs Viper: A Practical Comparison
+
+This document is written for Go developers and engineering organizations evaluating
+configuration management packages. It assumes you are **not** using remote configuration
+sources — which represents the majority of real-world Go projects.
+
+---
+
+## TL;DR
+
+| Capability | Viper | Figtree |
+|---|---|---|
+| CLI flags | ✅ (via pflag) | ✅ (via stdlib flag) |
+| Environment variables | ✅ | ✅ |
+| Config files (YAML/JSON/INI) | ✅ | ✅ |
+| File watching | ✅ | 🔜 planned v2.1.1+ |
+| Struct unmarshaling | ✅ | 🔜 planned v2.2.0+ |
+| Per-property validators | ❌ | ✅ 36 built-in |
+| Per-property callbacks | ❌ | ✅ |
+| Mutation tracking channel | ❌ | ✅ |
+| Property aliases | ⚠️ shallow | ✅ full propagation |
+| Property rules | ❌ | ✅ |
+| Struct tag validation (assure:) | ❌ | 🔜 planned v2.2.0+ |
+| Organizational branches | ❌ | 🔜 planned v2.3.0+ |
+| Known race conditions | ⚠️ yes | ✅ AI Battle Tested |
+| Remote config sources | ✅ | 🔜 planned |
+| stdlib flag compatibility | ❌ | ✅ |
+| Zero dependencies (core) | ❌ | ✅ |
+
+---
+
+## Philosophy
+
+**Viper** was designed to be the swiss army knife of Go configuration. It integrates
+with `pflag`, supports remote backends like etcd and Consul, and has accumulated years
+of community contributions. Its breadth is its strength and its weakness — the API
+surface is large, the concurrency model has known issues, and per-property behavior
+is not possible without wrapping viper yourself.
+
+**Figtree** was designed around a single premise: every configurable property in your
+application is a first-class citizen with its own validators, callbacks, aliases, and
+rules. The tree is the unit of organization. Properties are the unit of behavior.
+Mutations are observable. The API is opinionated so your application does not have to be.
+
+---
+
+## Feature Breakdown
+
+### CLI Flags
+
+Viper delegates flag parsing to `pflag`, a POSIX-compliant flag package that is itself
+a dependency. Figtree uses the Go standard library `flag` package directly, introducing
+zero additional dependencies for flag parsing.
+
+```go
+// Viper (requires pflag)
+pflag.String("host", "localhost", "database host")
+viper.BindPFlag("host", pflag.Lookup("host"))
+
+// Figtree
+figs.NewString("host", "localhost", "database host")
+```
+
+### Environment Variables
+
+Both packages support environment variable binding. Figtree resolves environment
+variables automatically by uppercasing the property name and does not require explicit
+binding calls.
+
+```go
+// Viper
+viper.SetEnvPrefix("APP")
+viper.AutomaticEnv()
+viper.BindEnv("host")
+
+// Figtree — automatic, no binding required
+figs.NewString("host", "localhost", "database host")
+// HOST=db.example.com ./myapp works automatically
+```
+
+### Config Files
+
+Both packages support YAML, JSON, and INI formats. Figtree resolves the config file
+path through a priority chain: `CONFIG_FILE` environment variable, `Options.ConfigFile`,
+package-level `ConfigFilePath`, then conventional filenames in the working directory.
+
+```go
+// Viper
+viper.SetConfigName("config")
+viper.SetConfigType("yaml")
+viper.AddConfigPath(".")
+viper.ReadInConfig()
+
+// Figtree
+figs := figtree.With(figtree.Options{ConfigFile: "config.yaml"})
+figs.Load()
+```
+
+### File Watching
+
+Viper provides `viper.WatchConfig()` with an `OnConfigChange` callback. Figtree provides
+`Options{Watch: true}` with mutations flowing through the existing `Mutations()` channel
+— no separate callback registration required. File-driven changes flow through the same
+validators, callbacks, and rules as programmatic changes.
+
+```go
+// Viper
+viper.WatchConfig()
+viper.OnConfigChange(func(e fsnotify.Event) {
+ // raw event, no validation, no type safety
+})
+
+// Figtree
+figs := figtree.With(figtree.Options{
+ Watch: true,
+ Tracking: true,
+ ConfigFile: "config.yaml",
+})
+figs.Load()
+for mutation := range figs.Mutations() {
+ log.Printf("%s changed: %v → %v", mutation.Property, mutation.Old, mutation.New)
+}
+```
+
+### Per-Property Validators
+
+Viper has no built-in validation. Developers must validate values after retrieval,
+scattering validation logic across the codebase. Figtree ships 36 built-in validators
+and supports custom `func(interface{}) error` validators registered per property.
+
+```go
+// Viper — validation is your problem
+host := viper.GetString("host")
+if host == "" {
+ return errors.New("host is required")
+}
+
+// Figtree — validation is declared at registration
+figs.NewString("host", "", "database host")
+figs.WithValidator("host", figtree.AssureStringNotEmpty)
+figs.WithValidator("host", figtree.AssureStringHasPrefix("postgres://"))
+// Parse() or Load() returns error if validation fails
+```
+
+The full validator table covers strings, booleans, integers, int64, float64, durations,
+lists, and maps. See the [Available Validators](README.md#available-validators) section
+for the complete reference.
+
+### Per-Property Callbacks
+
+Viper has no per-property callback system. Figtree supports three callback hooks per
+property: `CallbackAfterVerify` (on Parse/Load), `CallbackAfterRead` (on every getter
+call), and `CallbackAfterChange` (on every Store call and file-driven reload).
+
+```go
+// Viper — no equivalent
+
+// Figtree
+figs.WithCallback("host", figtree.CallbackAfterChange, func(value interface{}) error {
+ log.Printf("host changed to %v — reconnecting", value)
+ return reconnect(value.(string))
+})
+```
+
+### Mutation Tracking
+
+Viper provides a single `OnConfigChange` hook for file-driven changes only. Programmatic
+changes via `viper.Set()` produce no observable event. Figtree provides a buffered
+channel that receives a `Mutation` for every value change regardless of source — file,
+environment variable, flag, or programmatic `Store()` call.
+
+```go
+// Viper — only file changes, no channel
+viper.OnConfigChange(func(e fsnotify.Event) { ... })
+
+// Figtree — all changes, channel-based, select-compatible
+figs := figtree.With(figtree.Options{Tracking: true, Harvest: 100})
+go func() {
+ for mutation := range figs.Mutations() {
+ log.Printf("%s: %v → %v at %s",
+ mutation.Property, mutation.Old, mutation.New, mutation.When)
+ }
+}()
+```
+
+### Property Aliases
+
+Viper supports `viper.RegisterAlias("host", "h")` but the alias only applies at the
+getter level. Validators, callbacks, and setters do not propagate through aliases.
+Figtree aliases are full citizens — everything that works on the canonical name works
+identically on the alias.
+
+```go
+// Viper — alias is getter-only
+viper.RegisterAlias("verbose", "v")
+// viper.Set("v", true) does NOT trigger OnConfigChange for "verbose"
+
+// Figtree — alias propagates everywhere
+figs.NewBool("verbose", false, "enable verbose output")
+figs.WithAlias("verbose", "v")
+figs.WithValidator("verbose", figtree.AssureBoolTrue)
+figs.StoreString("v", "true") // validator fires
+*figs.Bool("verbose") // true
+*figs.Bool("v") // true
+```
+
+### Property Rules
+
+Viper has no concept of property-level rules. Figtree provides rules that govern how
+a property behaves at runtime, applied per-property or tree-wide.
+
+```go
+// Figtree rules — no Viper equivalent
+figs.WithRule("db-password", figtree.RulePreventChange) // immutable after Parse
+figs.WithRule("debug", figtree.RulePanicOnChange) // panic on change
+figs.WithTreeRule(figtree.RuleNoFlags) // disable all CLI flags
+figs.WithTreeRule(figtree.RuleNoEnv) // disable all env vars
+```
+
+Full rule reference:
+
+| Rule | Behavior |
+|---|---|
+| `RulePreventChange` | Blocks all Store calls after initial value is set |
+| `RulePanicOnChange` | Panics on any Store call |
+| `RuleNoValidations` | Skips all WithValidator assignments |
+| `RuleNoCallbacks` | Skips all WithCallback assignments |
+| `RuleNoFlags` | Disables CLI flag parsing for the tree |
+| `RuleNoEnv` | Skips all os.Getenv logic |
+| `RuleNoMaps` | Blocks NewMap, StoreMap, and Map |
+| `RuleNoLists` | Blocks NewList, StoreList, and List |
+| `RuleCondemnedFromResurrection` | Panics on Resurrect attempts |
+
+### Struct Unmarshaling with Validation
+
+Viper provides `viper.Unmarshal(&cfg)` which populates a struct from the config store.
+It has no validation layer — you get the values, validation is your responsibility.
+Figtree's `Unmarshal` populates structs and runs inline validators declared via the
+`assure:` struct tag, covering all 36 built-in validators.
+
+```go
+// Viper
+var cfg Config
+viper.Unmarshal(&cfg)
+// validate cfg yourself
+
+// Figtree
+type DatabaseConfig struct {
+ Host string `fig:"host" assure:"notEmpty|hasPrefix=postgres://"`
+ Port int `fig:"port" assure:"inRange=1024,65535"`
+ Timeout time.Duration `fig:"timeout" assure:"min=5s|max=2m"`
+}
+var cfg DatabaseConfig
+err := figs.Unmarshal(&cfg)
+// validation runs inline, UnmarshalError carries field, fig key, and failing token
+```
+
+### Concurrency
+
+Viper has well-documented race conditions that have been open issues for years. Safe
+concurrent use of viper requires external locking that the developer must implement
+and maintain. Figtree was designed with concurrency as a first-class concern — all
+internal operations use `sync.RWMutex` correctly, the mutations channel is safely
+buffered, and `Store()` releases locks before channel sends to prevent deadlock.
+
+---
+
+## Migration from Viper to Figtree
+
+The conceptual mapping is straightforward for projects not using remote config sources.
+
+### Installation
+
+```bash
+go get -u github.com/andreimerlescu/figtree/v2
+```
+
+### Import
+
+```go
+// Before
+import "github.com/spf13/viper"
+
+// After
+import "github.com/andreimerlescu/figtree/v2"
+```
+
+### Initialization
+
+```go
+// Viper
+viper.SetDefault("host", "localhost")
+viper.SetDefault("port", 5432)
+viper.AutomaticEnv()
+
+// Figtree
+figs := figtree.Grow()
+figs.NewString("host", "localhost", "database host")
+figs.NewInt("port", 5432, "database port")
+```
+
+### Reading Values
+
+```go
+// Viper
+host := viper.GetString("host")
+port := viper.GetInt("port")
+
+// Figtree
+host := *figs.String("host")
+port := *figs.Int("port")
+```
+
+### Writing Values
+
+```go
+// Viper
+viper.Set("host", "db.example.com")
+
+// Figtree
+figs.StoreString("host", "db.example.com")
+```
+
+### Config File Loading
+
+```go
+// Viper
+viper.SetConfigFile("config.yaml")
+viper.ReadInConfig()
+
+// Figtree
+figs := figtree.With(figtree.Options{ConfigFile: "config.yaml"})
+figs.Load()
+```
+
+### Struct Unmarshaling
+
+```go
+// Viper
+var cfg Config
+viper.Unmarshal(&cfg)
+
+// Figtree
+var cfg Config
+figs.Unmarshal(&cfg)
+```
+
+---
+
+## When to Choose Viper
+
+- Your project depends on `pflag` and you cannot migrate
+- You require remote configuration sources (etcd, Consul, Vault) today
+- You have deep existing viper integration with significant migration cost
+
+## When to Choose Figtree
+
+- You want per-property validation without writing it yourself
+- You want observable mutations via a channel
+- You want immutability rules on specific properties
+- You want struct unmarshaling with inline validation
+- You want a concurrency-safe configuration package
+- You are not using viper's remote configuration capabilities
+- You want zero non-stdlib dependencies in your configuration layer
+- You want organizational structure via branches (v2.3.0+)
+
+---
+
+## Summary
+
+For the majority of Go projects that use viper for flags, environment variables, and
+config files — and nothing more — figtree offers a more expressive, safer, and more
+maintainable alternative. The per-property model gives you validation, callbacks, rules,
+and mutation tracking that viper requires you to build yourself.
+
+If your project does not use viper's remote configuration sources, figtree is worth
+evaluating as a direct replacement.
+
+---
+
+*Figtree is maintained by [@andreimerlescu](https://github.com/andreimerlescu).*
+*Current stable release: v2.1.0*
+*License: MIT*
diff --git a/README.md b/README.md
index 8d68a59..17bcb85 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,11 @@
# Fig Tree
-[](https://opensource.org/licenses/MIT)
+
Fig Tree is a command line utility configuration manager that you can refer to as `figs`, as you conFIGure your
-application's runtime.
+application's runtime. Check out [ABOUT.md](/ABOUT.md) if you want to learn about the origins of the package itself and why I built it.
-
+[](https://opensource.org/licenses/MIT)
## Installation
@@ -15,6 +15,34 @@ To use `figtree` in your project, `go get` it...
go get -u github.com/andreimerlescu/figtree/v2
```
+## Feature Comparison of Figtree vs Viper
+
+Figtree was designed to be a replacement for Viper since I prefer fruit over fangs of a snake and I am a programmer capable of investing the energy into giving you an alternative that packs a strong punch.
+
+Think of it this way: _Viper_ is for Eve and _Figtree_ is for Adam.
+
+| Capability | Viper | Figtree |
+|---|---|---|
+| CLI flags | ✅ (via pflag) | ✅ (via stdlib flag) |
+| Environment variables | ✅ | ✅ |
+| Config files (YAML/JSON/INI) | ✅ | ✅ |
+| File watching | ✅ | 🔜 planned v2.1.1+ |
+| Struct unmarshaling | ✅ | 🔜 planned v2.2.0+ |
+| Per-property validators | ❌ | ✅ 36 built-in |
+| Per-property callbacks | ❌ | ✅ |
+| Mutation tracking channel | ❌ | ✅ |
+| Property aliases | ⚠️ shallow | ✅ full propagation |
+| Property rules | ❌ | ✅ |
+| Struct tag validation (assure:) | ❌ | 🔜 planned v2.2.0+ |
+| Organizational branches | ❌ | 🔜 planned v2.3.0+ |
+| Known race conditions | ⚠️ yes | ✅ fixed |
+| Remote config sources | ✅ | 🔜 planned |
+| stdlib flag compatibility | ❌ | ✅ |
+| Zero dependencies (core) | ❌ | ✅ |
+
+[Read full case study comparison...](/COMPARISON.md)
+
+
## Usage
To use **figs** package in your Go code, you need to import it:
@@ -266,6 +294,7 @@ With callbacks, you can really slow the performance down of `figtree`, but when
At the end of the day, you'll know what's best to use. I build what I build because its the best that I use.
+
### Complex Example Usage
```go
diff --git a/logo.jpeg b/logo.jpeg
new file mode 100644
index 0000000..7f36050
Binary files /dev/null and b/logo.jpeg differ